diff --git a/configure.ac b/configure.ac index c4042828a..90191ab53 100644 --- a/configure.ac +++ b/configure.ac @@ -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" diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 7930a0f04..f6f99cd93 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -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; } diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 1a7b191a8..ce3595cdc 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -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"))); diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c index c996ab723..964a02cf2 100644 --- a/coreapi/bellesip_sal/sal_op_call_transfer.c +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -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; } diff --git a/coreapi/bellesip_sal/sal_op_events.c b/coreapi/bellesip_sal/sal_op_events.c index 2c490ce6b..cf67c992d 100644 --- a/coreapi/bellesip_sal/sal_op_events.c +++ b/coreapi/bellesip_sal/sal_op_events.c @@ -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))); diff --git a/coreapi/bellesip_sal/sal_op_info.c b/coreapi/bellesip_sal/sal_op_info.c index 3b329515f..9abc73818 100644 --- a/coreapi/bellesip_sal/sal_op_info.c +++ b/coreapi/bellesip_sal/sal_op_info.c @@ -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); } diff --git a/coreapi/bellesip_sal/sal_op_presence.c b/coreapi/bellesip_sal/sal_op_presence.c index ca6b86cab..5ea4cfe7b 100644 --- a/coreapi/bellesip_sal/sal_op_presence.c +++ b/coreapi/bellesip_sal/sal_op_presence.c @@ -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")); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 16fa1ed1f..cba47183e 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -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){ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index db5af1ba7..ae2ff5f01 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -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; } /** diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 6aa9fb015..ee9585728 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -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; diff --git a/coreapi/private.h b/coreapi/private.h index b508f366a..7c8dd1667 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -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; diff --git a/include/sal/sal.h b/include/sal/sal.h index 239bd949c..4305e4df0 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -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); diff --git a/tester/call_tester.c b/tester/call_tester.c index 8486d003f..74364fb66 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -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} diff --git a/tester/liblinphone_tester.h b/tester/liblinphone_tester.h index 36dc323af..70aeaf83e 100644 --- a/tester/liblinphone_tester.h +++ b/tester/liblinphone_tester.h @@ -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;