From 4073c6e0d0eaf331da8c458a3504b5c8f5924b62 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Thu, 23 Jul 2015 09:20:35 +0200 Subject: [PATCH] Restaure previous state in case of call update failure due to pending transaction --- coreapi/bellesip_sal/sal_impl.c | 10 ++++ coreapi/bellesip_sal/sal_impl.h | 1 + coreapi/bellesip_sal/sal_op_call.c | 7 +++ coreapi/bellesip_sal/sal_op_impl.c | 5 +- coreapi/bellesip_sal/sal_op_info.c | 1 + coreapi/linphonecore.c | 11 +++- include/sal/sal.h | 5 ++ tester/call_tester.c | 91 +++++++++++++++++++++++++++--- 8 files changed, 118 insertions(+), 13 deletions(-) diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 957a0e4ca..6e3a6cba9 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -490,6 +490,7 @@ Sal * sal_init(){ sal->tls_verify_cn=TRUE; sal->refresher_retry_after=60000; /*default value in ms*/ sal->enable_sip_update=TRUE; + sal->pending_trans_checking=TRUE; return sal; } @@ -1172,3 +1173,12 @@ void sal_default_set_sdp_handling(Sal *sal, SalOpSDPHandling sdp_handling_method if (sdp_handling_method != SalOpSDPNormal ) ms_message("Enabling special SDP handling for all new SalOp in Sal[%p]!", sal); sal->default_sdp_handling = sdp_handling_method; } + +bool_t sal_pending_trans_checking_enabled(const Sal *sal) { + return sal->pending_trans_checking; +} + +int sal_enable_pending_trans_checking(Sal *sal, bool_t value) { + sal->pending_trans_checking = value; + return 0; +} diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 4cceba127..eae0c6bb3 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -51,6 +51,7 @@ struct Sal{ bool_t no_initial_route; bool_t enable_sip_update; /*true by default*/ SalOpSDPHandling default_sdp_handling; + bool_t pending_trans_checking; /*testing purpose*/ }; typedef enum SalOpState { diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index acc629f39..f6e7087bb 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -889,6 +889,8 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti int sal_call_update(SalOp *op, const char *subject, bool_t no_user_consent){ belle_sip_request_t *update; belle_sip_dialog_state_t state=belle_sip_dialog_get_state(op->dialog); + belle_sip_dialog_enable_pending_trans_checking(op->dialog,op->base.root->pending_trans_checking); + /*check for dialog state*/ if ( state == BELLE_SIP_DIALOG_CONFIRMED) { if (no_user_consent) @@ -906,6 +908,11 @@ int sal_call_update(SalOp *op, const char *subject, bool_t no_user_consent){ sal_op_fill_invite(op, update); return sal_op_send_request(op,update); } + /*it failed why ?*/ + if (belle_sip_dialog_request_pending(op->dialog)) + sal_error_info_set(&op->error_info,SalReasonRequestPending,491,NULL,NULL); + else + sal_error_info_set(&op->error_info,SalReasonUnknown,500,NULL,NULL); return -1; } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index 7361486e7..3338356a1 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -613,7 +613,10 @@ void set_or_update_dialog(SalOp* op, belle_sip_dialog_t* dialog) { unlink_op_with_dialog(op,op->dialog); op->dialog=NULL; } - if (dialog) op->dialog=link_op_with_dialog(op,dialog); + if (dialog) { + op->dialog=link_op_with_dialog(op,dialog); + belle_sip_dialog_enable_pending_trans_checking(dialog,op->base.root->pending_trans_checking); + } } sal_op_unref(op); } diff --git a/coreapi/bellesip_sal/sal_op_info.c b/coreapi/bellesip_sal/sal_op_info.c index 9abc73818..e8be5f27c 100644 --- a/coreapi/bellesip_sal/sal_op_info.c +++ b/coreapi/bellesip_sal/sal_op_info.c @@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. int sal_send_info(SalOp *op, const char *from, const char *to, const SalBody *body){ if (op->dialog){ + belle_sip_dialog_enable_pending_trans_checking(op->dialog,op->base.root->pending_trans_checking); belle_sip_request_t *req=belle_sip_dialog_create_queued_request(op->dialog,"INFO"); sal_op_add_body(op,(belle_sip_message_t*)req,body); return sal_op_send_request(op,req); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index f0e7254dc..104acb0f2 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -3270,12 +3270,13 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){ **/ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){ int err=0; - LinphoneCallState nextstate; + LinphoneCallState nextstate, initial_state; + #if defined(VIDEO_ENABLED) && defined(BUILD_UPNP) bool_t has_video = FALSE; #endif - switch(call->state){ + switch(initial_state=call->state){ case LinphoneCallIncomingReceived: case LinphoneCallIncomingEarlyMedia: case LinphoneCallOutgoingRinging: @@ -3328,7 +3329,11 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho } } #endif //defined(VIDEO_ENABLED) && defined(BUILD_UPNP) - err = linphone_core_start_update_call(lc, call); + if ((err = linphone_core_start_update_call(lc, call)) && call->state!=initial_state) { + /*Restore initial state*/ + linphone_call_set_state(call,initial_state,NULL); + } + }else{ #ifdef VIDEO_ENABLED if ((call->videostream != NULL) && (call->state == LinphoneCallStreamsRunning)) { diff --git a/include/sal/sal.h b/include/sal/sal.h index bceff451d..a404eb0b9 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -800,6 +800,11 @@ LINPHONE_PUBLIC void sal_set_recv_error(Sal *sal,int value); /*always answer 480 if value=true*/ LINPHONE_PUBLIC void sal_enable_unconditional_answer(Sal *sal,int value); +LINPHONE_PUBLIC bool_t sal_pending_trans_checking_enabled(const Sal *sal) ; +LINPHONE_PUBLIC int sal_enable_pending_trans_checking(Sal *sal, bool_t value) ; + + + /*refresher retry after value in ms*/ LINPHONE_PUBLIC void sal_set_refresher_retry_after(Sal *sal,int value); LINPHONE_PUBLIC int sal_get_refresher_retry_after(const Sal *sal); diff --git a/tester/call_tester.c b/tester/call_tester.c index 98469027a..419089f91 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -2829,17 +2829,15 @@ static void call_established_with_complex_rejected_operation(void) { linphone_call_send_info_message(linphone_core_get_current_call(marie->lc),linphone_core_create_info_message(marie->lc)); - /*by chance, UPDATES can be sent in // to invite, but drawback is that it will not be rejected with 491*/ params=linphone_core_create_call_params(marie->lc,linphone_core_get_current_call(marie->lc)); - params->no_user_consent=TRUE; + sal_enable_pending_trans_checking(marie->lc->sal,FALSE); /*to allow // transactions*/ + linphone_core_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMU",8000,1),TRUE); + linphone_core_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMA",8000,1),FALSE); + linphone_core_update_call( marie->lc ,linphone_core_get_current_call(marie->lc) ,params); - - - - linphone_call_params_destroy(params); BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,3)); @@ -2859,6 +2857,58 @@ static void call_established_with_complex_rejected_operation(void) { linphone_core_manager_destroy(pauline); } +static void call_established_with_rejected_info_during_reinvite(void) { + + LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); + bool_t call_ok=FALSE; + + BC_ASSERT_TRUE((call_ok=call(pauline,marie))); + if (call_ok){ + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,1)); + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,1)); + + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMU",8000,1),FALSE); /*disable PCMU*/ + linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ + linphone_core_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMU",8000,1),FALSE); /*disable PCMU*/ + linphone_core_enable_payload_type(marie->lc,linphone_core_find_payload_type(marie->lc,"PCMA",8000,1),TRUE); /*enable PCMA*/ + + /*just to authenticate marie*/ + linphone_call_send_info_message(linphone_core_get_current_call(marie->lc),linphone_core_create_info_message(marie->lc)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_inforeceived,1)); + BC_ASSERT_EQUAL(pauline->stat.number_of_inforeceived,1, int, "%d"); + /*to give time for 200ok to arrive*/ + wait_for_until(marie->lc,pauline->lc,NULL,0,1000); + + + //sal_enable_pending_trans_checking(marie->lc->sal,FALSE); /*to allow // transactions*/ + + linphone_call_send_info_message(linphone_core_get_current_call(marie->lc),linphone_core_create_info_message(marie->lc)); + + //sal_set_send_error(marie->lc->sal, -1); /*to avoid 491 pending to be sent*/ + + linphone_core_update_call( pauline->lc + ,linphone_core_get_current_call(pauline->lc) + ,linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))); + + + + wait_for_until(pauline->lc,pauline->lc,NULL,0,2000); /*to avoid 491 pending to be sent to early*/ + + + BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + } + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + static void call_established_with_rejected_reinvite(void) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); @@ -2987,22 +3037,32 @@ static void call_redirect(void){ } -static void call_established_with_rejected_reinvite_with_error(void) { +static void call_established_with_rejected_reinvite_with_error_base(bool_t trans_pending) { LinphoneCoreManager* marie = linphone_core_manager_new("marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new(transport_supported(LinphoneTransportTls) ? "pauline_rc" : "pauline_tcp_rc"); bool_t call_ok=TRUE; + int result; BC_ASSERT_TRUE((call_ok=call(pauline,marie))); if (call_ok){ linphone_core_enable_payload_type(pauline->lc,linphone_core_find_payload_type(pauline->lc,"PCMA",8000,1),TRUE); /*add PCMA*/ - sal_enable_unconditional_answer(marie->lc->sal,TRUE); + if (trans_pending) { + LinphoneInfoMessage * info = linphone_core_create_info_message(pauline->lc); + linphone_call_send_info_message(linphone_core_get_current_call(pauline->lc),info); - linphone_core_update_call( pauline->lc + } else + sal_enable_unconditional_answer(marie->lc->sal,TRUE); + + result = linphone_core_update_call( pauline->lc ,linphone_core_get_current_call(pauline->lc) ,linphone_call_get_current_params(linphone_core_get_current_call(pauline->lc))); + if (trans_pending) + BC_ASSERT_NOT_EQUAL(result,0, int, "%d"); + else + BC_ASSERT_EQUAL(result,0,int, "%d"); BC_ASSERT_TRUE(wait_for(marie->lc,pauline->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); @@ -3012,6 +3072,9 @@ static void call_established_with_rejected_reinvite_with_error(void) { check_call_state(pauline,LinphoneCallStreamsRunning); check_call_state(marie,LinphoneCallStreamsRunning); + if (!trans_pending) + sal_enable_unconditional_answer(marie->lc->sal,FALSE); + /*just to sleep*/ linphone_core_terminate_all_calls(pauline->lc); BC_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); @@ -3022,6 +3085,14 @@ static void call_established_with_rejected_reinvite_with_error(void) { linphone_core_manager_destroy(pauline); } +static void call_established_with_rejected_reinvite_with_error(void) { + call_established_with_rejected_reinvite_with_error_base(FALSE); +} + +static void call_established_with_rejected_reinvite_with_trans_pending_error(void) { + call_established_with_rejected_reinvite_with_error_base(TRUE); +} + static void call_rejected_because_wrong_credentials_with_params(const char* user_agent,bool_t enable_auth_req_cb) { LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc"); LinphoneAuthInfo* good_auth_info=linphone_auth_info_clone(linphone_core_find_auth_info(marie->lc,NULL,linphone_address_get_username(marie->identity),NULL)); @@ -4339,7 +4410,9 @@ test_t call_tests[] = { { "Call established with rejected RE-INVITE",call_established_with_rejected_reinvite}, { "Call established with rejected incoming RE-INVITE", call_established_with_rejected_incoming_reinvite }, { "Call established with rejected RE-INVITE in error", call_established_with_rejected_reinvite_with_error}, + { "Call established with rejected RE-INVITE with trans pending error", call_established_with_rejected_reinvite_with_trans_pending_error}, { "Call established with complex rejected operation",call_established_with_complex_rejected_operation}, + { "Call established with rejected info during re-invite",call_established_with_rejected_info_during_reinvite}, { "Call redirected by callee", call_redirect}, { "Call with specified codec bitrate", call_with_specified_codec_bitrate}, { "Call with in-dialog UPDATE request", call_with_in_dialog_update },