Commit 9a671657 authored by Simon Morlat's avatar Simon Morlat
Browse files

make use of bellesip's new dialog's request queue to fix bugs around transfer notification

add notification of failed transfers (new test in call suite for that)
In case of failed transfer, referer call is resumed (if necessary) and notified of the failure.
remove deprecated code.
parent bcfc3d9d
......@@ -681,7 +681,7 @@ if test x$enable_msg_storage != xfalse; then
fi
PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.1.0])
PKG_CHECK_MODULES(BELLESIP, [belle-sip >= 1.2.0])
SIPSTACK_CFLAGS="$BELLESIP_CFLAGS"
SIPSTACK_LIBS="$BELLESIP_LIBS"
......
......@@ -565,26 +565,16 @@ void sal_use_session_timers(Sal *ctx, int expires){
ctx->session_expires=expires;
return ;
}
void sal_use_double_registrations(Sal *ctx, bool_t enabled){
ms_warning("sal_use_double_registrations is deprecated");
return ;
}
void sal_reuse_authorization(Sal *ctx, bool_t enabled){
ms_warning("sal_reuse_authorization is deprecated");
return ;
}
void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec){
ctx->one_matching_codec=one_matching_codec;
}
void sal_use_rport(Sal *ctx, bool_t use_rports){
belle_sip_provider_enable_rport(ctx->prov,use_rports);
ms_message("Sal use rport [%s]",use_rports?"enabled":"disabled");
return ;
}
void sal_use_101(Sal *ctx, bool_t use_101){
ms_warning("sal_use_101 is deprecated");
return ;
}
static void set_tls_properties(Sal *ctx){
belle_sip_listening_point_t *lp=belle_sip_provider_get_listening_point(ctx->prov,"TLS");
......@@ -705,10 +695,6 @@ const char* sal_op_type_to_string(const SalOpType type) {
}
}
void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){
ms_warning("sal_expire_old_registration_contacts not implemented ");
}
void sal_use_dates(Sal *ctx, bool_t enabled){
ctx->use_dates=enabled;
}
......
......@@ -710,7 +710,7 @@ SalMediaDescription * sal_call_get_final_media_description(SalOp *h){
int sal_call_send_dtmf(SalOp *h, char dtmf){
if (h->dialog){
belle_sip_request_t *req=belle_sip_dialog_create_request(h->dialog,"INFO");
belle_sip_request_t *req=belle_sip_dialog_create_queued_request(h->dialog,"INFO");
if (req){
int bodylen;
char dtmf_body[128]={0};
......@@ -789,7 +789,7 @@ void sal_call_send_vfu_request(SalOp *op){
size_t content_lenth = sizeof(info_body) - 1;
belle_sip_dialog_state_t dialog_state=op->dialog?belle_sip_dialog_get_state(op->dialog):BELLE_SIP_DIALOG_NULL; /*no dialog = dialog in NULL state*/
if (dialog_state == BELLE_SIP_DIALOG_CONFIRMED) {
belle_sip_request_t* info = belle_sip_dialog_create_request(op->dialog,"INFO");
belle_sip_request_t* info = belle_sip_dialog_create_queued_request(op->dialog,"INFO");
int error=TRUE;
if (info) {
belle_sip_message_add_header(BELLE_SIP_MESSAGE(info),BELLE_SIP_HEADER(belle_sip_header_content_type_create("application","media_control+xml")));
......
......@@ -133,39 +133,49 @@ SalOp *sal_call_get_replaces(SalOp *op){
return NULL;
}
static int send_notify_for_refer(SalOp* op, const char *sipfrag){
belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY");
static int send_notify_for_refer(SalOp* op, int code, const char *reason){
belle_sip_request_t* notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY");
char *sipfrag=belle_sip_strdup_printf("SIP/2.0 %i %s\r\n",code,reason);
size_t content_length=strlen(sipfrag);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,-1)));
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_ACTIVE,-1)));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),belle_sip_header_create("Event","refer"));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(belle_sip_header_content_type_create("message","sipfrag")));
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify),BELLE_SIP_HEADER(belle_sip_header_content_length_create(content_length)));
belle_sip_message_set_body(BELLE_SIP_MESSAGE(notify),sipfrag,content_length);
belle_sip_message_assign_body(BELLE_SIP_MESSAGE(notify),sipfrag,content_length);
return sal_op_send_request(op,notify);
}
static void notify_last_response(SalOp *op, SalOp *newcall){
belle_sip_client_transaction_t *tr=newcall->pending_client_trans;
belle_sip_response_t *resp=NULL;
if (tr){
resp=belle_sip_transaction_get_response((belle_sip_transaction_t*)tr);
}
if (resp==NULL){
send_notify_for_refer(op, 100, "Trying");
}else{
send_notify_for_refer(op, belle_sip_response_get_status_code(resp), belle_sip_response_get_reason_phrase(resp));
}
}
int sal_call_notify_refer_state(SalOp *op, SalOp *newcall){
if(belle_sip_dialog_get_state(op->dialog) == BELLE_SIP_DIALOG_TERMINATED){
return 0;
}
belle_sip_dialog_state_t state=newcall->dialog?belle_sip_dialog_get_state(newcall->dialog):BELLE_SIP_DIALOG_NULL;
switch(state) {
case BELLE_SIP_DIALOG_NULL:
case BELLE_SIP_DIALOG_EARLY:
send_notify_for_refer(op,"SIP/2.0 100 Trying\r\n");
break;
case BELLE_SIP_DIALOG_CONFIRMED:
if(send_notify_for_refer(op,"SIP/2.0 200 Ok\r\n")) {
/* we need previous notify transaction to complete, so buffer the request for later*/
/*op->sipfrag_pending="SIP/2.0 200 Ok\r\n";*/
ms_error("Cannot notify 200 ok frag to [%p] for new op [%p]",op,newcall);
}
break;
default:
break;
case BELLE_SIP_DIALOG_EARLY:
send_notify_for_refer(op, 100, "Trying");
break;
case BELLE_SIP_DIALOG_CONFIRMED:
send_notify_for_refer(op, 200, "Ok");
break;
case BELLE_SIP_DIALOG_TERMINATED:
case BELLE_SIP_DIALOG_NULL:
notify_last_response(op,newcall);
break;
}
return 0;
}
......
......@@ -248,6 +248,10 @@ int sal_subscribe(SalOp *op, const char *from, const char *to, const char *event
belle_sip_transaction_t *last=belle_sip_dialog_get_last_transaction(op->dialog);
belle_sip_message_t *msg=BELLE_SIP_MESSAGE(belle_sip_transaction_get_request(last));
req=belle_sip_dialog_create_request(op->dialog,"SUBSCRIBE");
if (!req) {
ms_error("Cannot create subscribe refresh.");
return -1;
}
if (expires==-1){
belle_sip_header_expires_t *eh=belle_sip_message_get_header_by_type(msg,belle_sip_header_expires_t);
expires=belle_sip_header_expires_get_expires(eh);
......@@ -293,7 +297,7 @@ int sal_notify(SalOp *op, const SalBody *body){
if (!op->dialog) return -1;
if (!(notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"))) return -1;
if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1;
if (set_event_name(op,(belle_sip_message_t*)notify)==-1){
belle_sip_object_unref(notify);
......@@ -310,7 +314,7 @@ int sal_notify(SalOp *op, const SalBody *body){
int sal_notify_close(SalOp *op){
belle_sip_request_t* notify;
if (!op->dialog) return -1;
if (!(notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY"))) return -1;
if (!(notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY"))) return -1;
set_event_name(op,(belle_sip_message_t*)notify);
belle_sip_message_add_header(BELLE_SIP_MESSAGE(notify)
,BELLE_SIP_HEADER(belle_sip_header_subscription_state_create(BELLE_SIP_SUBSCRIPTION_STATE_TERMINATED,-1)));
......
......@@ -21,7 +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_request_t *req=belle_sip_dialog_create_request(op->dialog,"INFO");
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);
}
......
......@@ -306,7 +306,7 @@ int sal_subscribe_presence(SalOp *op, const char *from, const char *to, int expi
static belle_sip_request_t *create_presence_notify(SalOp *op){
belle_sip_request_t* notify=belle_sip_dialog_create_request(op->dialog,"NOTIFY");
belle_sip_request_t* notify=belle_sip_dialog_create_queued_request(op->dialog,"NOTIFY");
if (!notify) return NULL;
belle_sip_message_add_header((belle_sip_message_t*)notify,belle_sip_header_create("Event","presence"));
......
......@@ -467,7 +467,6 @@ static void call_resumed(LinphoneCore *lc, LinphoneCall *call){
if(lc->vtable.display_status)
lc->vtable.display_status(lc,_("We have been resumed."));
linphone_call_set_state(call,LinphoneCallStreamsRunning,"Connected (streams running)");
linphone_call_set_transfer_state(call, LinphoneCallIdle);
}
static void call_paused_by_remote(LinphoneCore *lc, LinphoneCall *call){
......@@ -569,6 +568,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
char *msg603=_("Call declined.");
const char *msg=details;
LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer(op);
LinphoneCall *referer=call->referer;
if (call==NULL){
ms_warning("Call faillure reported on already terminated call.");
......@@ -650,11 +650,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
}
linphone_core_stop_ringing(lc);
linphone_call_stop_media_streams (call);
if (call->referer && linphone_call_get_state(call->referer)==LinphoneCallPaused && call->referer->was_automatically_paused){
/*resume to the call that send us the refer automatically*/
linphone_core_resume_call(lc,call->referer);
}
linphone_call_stop_media_streams(call);
#ifdef BUILD_UPNP
linphone_call_delete_upnp_session(call);
......@@ -673,6 +669,22 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
} else {
linphone_call_set_state(call,LinphoneCallError,msg);
}
if (referer){
/*
* 1- resume call automatically if we had to pause it before to execute the transfer
* 2- notify other party of the transfer faillure
* This must be done at the end because transferer call can't be resumed until transfer-target call is changed to error state.
* This must be done in this order because if the notify transaction will prevent the resume transaction to take place.
* On the contrary, the notify transaction is queued and then executed after the resume completes.
**/
if (linphone_call_get_state(referer)==LinphoneCallPaused && referer->was_automatically_paused){
/*resume to the call that send us the refer automatically*/
linphone_core_resume_call(lc,referer);
referer->was_automatically_paused=FALSE;
}
linphone_core_notify_refer_state(lc,referer,call);
}
}
static void call_released(SalOp *op){
......
......@@ -642,10 +642,6 @@ static void linphone_call_set_terminated(LinphoneCall *call){
linphone_core_stop_dtmf(lc);
call->ringing_beep=FALSE;
}
if (call->referer){
linphone_call_unref(call->referer);
call->referer=NULL;
}
}
void linphone_call_fix_call_parameters(LinphoneCall *call){
......@@ -727,7 +723,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
default:
break;
}
linphone_call_set_terminated (call);
linphone_call_set_terminated(call);
}
if (cstate == LinphoneCallConnected) {
call->log->status=LinphoneCallSuccess;
......@@ -744,9 +740,9 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
call->op=NULL;
}
/*it is necessary to reset pointers to other call to prevent circular references that would result in memory never freed.*/
if (call->transferer){
linphone_call_unref(call->transferer);
call->transferer=NULL;
if (call->referer){
linphone_call_unref(call->referer);
call->referer=NULL;
}
if (call->transfer_target){
linphone_call_unref(call->transfer_target);
......@@ -782,8 +778,9 @@ static void linphone_call_destroy(LinphoneCall *obj)
if (obj->refer_to){
ms_free(obj->refer_to);
}
if (obj->transferer){
linphone_call_unref(obj->transferer);
if (obj->referer){
linphone_call_unref(obj->referer);
obj->referer=NULL;
}
if (obj->transfer_target){
linphone_call_unref(obj->transfer_target);
......@@ -961,7 +958,7 @@ const char *linphone_call_get_refer_to(const LinphoneCall *call){
* The call in which the transfer request was received is returned in this case.
**/
LinphoneCall *linphone_call_get_transferer_call(const LinphoneCall *call){
return call->transferer;
return call->referer;
}
/**
......
......@@ -617,9 +617,6 @@ static void sip_config_read(LinphoneCore *lc)
}
sal_use_rport(lc->sal,lp_config_get_int(lc->config,"sip","use_rport",1));
sal_use_101(lc->sal,lp_config_get_int(lc->config,"sip","use_101",1));
sal_reuse_authorization(lc->sal, lp_config_get_int(lc->config,"sip","reuse_authorization",0));
sal_expire_old_registration_contacts(lc->sal,lp_config_get_int(lc->config,"sip","expire_old_registration_contacts",0));
ipv6=lp_config_get_int(lc->config,"sip","use_ipv6",-1);
if (ipv6==-1){
......@@ -733,7 +730,6 @@ static void sip_config_read(LinphoneCore *lc)
lc->sip_conf.tcp_tls_keepalive=lp_config_get_int(lc->config,"sip","tcp_tls_keepalive",0);
linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0));
sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0));
sal_use_double_registrations(lc->sal,lp_config_get_int(lc->config,"sip","use_double_registrations",1));
sal_use_dates(lc->sal,lp_config_get_int(lc->config,"sip","put_date",0));
}
......@@ -2328,7 +2324,7 @@ void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call){
if (call->refer_pending){
LinphoneCallParams *cp=linphone_core_create_default_call_parameters(lc);
LinphoneCall *newcall;
cp->has_video &= !!lc->video_policy.automatically_initiate;
cp->has_video = call->current_params.has_video; /*start the call to refer-target with video enabled if original call had video*/
cp->referer=call;
ms_message("Starting new call to refered address %s",call->refer_to);
call->refer_pending=FALSE;
......@@ -2681,9 +2677,6 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
linphone_call_unref(call);
return NULL;
}
if (params && params->referer){
call->transferer=linphone_call_ref(params->referer);
}
/* this call becomes now the current one*/
lc->current_call=call;
......
......@@ -157,7 +157,6 @@ struct _LinphoneCall
SalMediaDescription *localdesc;
SalMediaDescription *resultdesc;
LinphoneCallDir dir;
LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/
struct _RtpProfile *audio_profile;
struct _RtpProfile *video_profile;
struct _LinphoneCallLog *log;
......@@ -198,7 +197,7 @@ struct _LinphoneCall
int ping_time;
unsigned int remote_session_id;
unsigned int remote_session_ver;
LinphoneCall *transferer; /*if this call is the result of a transfer, transferer points to the call from which the transfer request was received.*/
LinphoneCall *referer; /*when this call is the result of a transfer, referer is set to the original call that caused the transfer*/
LinphoneCall *transfer_target;/*if this call received a transfer request, then transfer_target points to the new call created to the refer target */
bool_t refer_pending;
bool_t media_pending;
......
......@@ -436,13 +436,9 @@ void sal_disable_tunnel(Sal *ctx);
* */
unsigned int sal_get_keepalive_period(Sal *ctx);
void sal_use_session_timers(Sal *ctx, int expires);
void sal_use_double_registrations(Sal *ctx, bool_t enabled);
void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled);
void sal_use_dates(Sal *ctx, bool_t enabled);
void sal_reuse_authorization(Sal *ctx, bool_t enabled);
void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec);
void sal_use_rport(Sal *ctx, bool_t use_rports);
void sal_use_101(Sal *ctx, bool_t use_101);
void sal_enable_auto_contacts(Sal *ctx, bool_t enabled);
void sal_set_root_ca(Sal* ctx, const char* rootCa);
const char *sal_get_root_ca(Sal* ctx);
......
......@@ -75,6 +75,7 @@ void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered,
case LinphoneCallOutgoingEarlyMedia :counters->number_of_LinphoneTransferCallOutgoingEarlyMedia++;break;
case LinphoneCallConnected :counters->number_of_LinphoneTransferCallConnected++;break;
case LinphoneCallStreamsRunning :counters->number_of_LinphoneTransferCallStreamsRunning++;break;
case LinphoneCallError :counters->number_of_LinphoneTransferCallError++;break;
default:
CU_FAIL("unexpected event");break;
}
......@@ -993,7 +994,7 @@ static void simple_call_transfer(void) {
ms_list_free(lcs);
}
static void mean_call_transfer(void) {
static void unattended_call_transfer(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCoreManager* laure = linphone_core_manager_new( "laure_rc");
......@@ -1039,6 +1040,37 @@ static void mean_call_transfer(void) {
ms_list_free(lcs);
}
static void unattended_call_transfer_with_error(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
LinphoneCall* pauline_called_by_marie;
MSList* lcs=ms_list_append(NULL,marie->lc);
lcs=ms_list_append(lcs,pauline->lc);
CU_ASSERT_TRUE(call(marie,pauline));
pauline_called_by_marie=linphone_core_get_current_call(marie->lc);
reset_counters(&marie->stat);
reset_counters(&pauline->stat);
linphone_core_transfer_call(marie->lc,pauline_called_by_marie,"unknown_user");
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallRefered,1,2000));
/*Pauline starts the transfer*/
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingInit,1,2000));
/* and immediately get an error*/
CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallError,1,2000));
/*the error must be reported back to marie*/
CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneTransferCallError,1,2000));
linphone_core_manager_destroy(marie);
linphone_core_manager_destroy(pauline);
ms_list_free(lcs);
}
static void call_transfer_existing_call_outgoing_call(void) {
LinphoneCoreManager* marie = linphone_core_manager_new( "marie_rc");
LinphoneCoreManager* pauline = linphone_core_manager_new( "pauline_rc");
......@@ -1143,7 +1175,8 @@ test_t call_tests[] = {
{ "Call with privacy", call_with_privacy },
{ "Simple conference", simple_conference },
{ "Simple call transfer", simple_call_transfer },
{ "Mean call transfer", mean_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 with ICE", call_with_ice },
{ "Call with custom headers",call_with_custom_headers}
......
......@@ -109,6 +109,7 @@ typedef struct _stats {
int number_of_LinphoneTransferCallOutgoingEarlyMedia;
int number_of_LinphoneTransferCallConnected;
int number_of_LinphoneTransferCallStreamsRunning;
int number_of_LinphoneTransferCallError;
int number_of_LinphoneMessageReceived;
int number_of_LinphoneMessageReceivedLegacy;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment