From 615fb7ad5d98d227751fb9c9d14e51c72dcbda68 Mon Sep 17 00:00:00 2001 From: Jehan Monnier Date: Fri, 15 Feb 2013 18:47:46 +0100 Subject: [PATCH] continue call transfer impl --- coreapi/Makefile.am | 3 +- coreapi/bellesip_sal/sal_impl.h | 4 +- coreapi/bellesip_sal/sal_op_call.c | 122 +------------ coreapi/bellesip_sal/sal_op_call_transfer.c | 181 ++++++++++++++++++++ coreapi/linphonecall.c | 3 + tester/call_tester.c | 17 +- tester/liblinphone_tester.c | 2 + tester/liblinphone_tester.h | 7 +- 8 files changed, 214 insertions(+), 125 deletions(-) create mode 100644 coreapi/bellesip_sal/sal_op_call_transfer.c diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index 40a7f99d9..70a7f82b5 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -58,7 +58,8 @@ liblinphone_la_SOURCES+= bellesip_sal/sal_address_impl.c \ bellesip_sal/sal_op_registration.c \ bellesip_sal/sal_sdp.c \ bellesip_sal/sal_op_message.c \ - bellesip_sal/sal_op_presence.c + bellesip_sal/sal_op_presence.c \ + bellesip_sal/sal_op_call_transfer.c else liblinphone_la_SOURCES+= sal_eXosip2.c sal_eXosip2.h\ sal_eXosip2_sdp.c \ diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 1e3962221..424fc6961 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -92,5 +92,7 @@ void sal_compute_sal_errors_from_code(int code ,SalError* sal_err,SalReason* sal void sal_op_presence_fill_cbs(SalOp*op); /*messaging*/ void sal_op_message_fill_cbs(SalOp*op); - +/*call transfert*/ +void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event); +void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event); #endif /* SAL_IMPL_H_ */ diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index f0acc8112..14ea90b56 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -19,7 +19,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "sal_impl.h" #include "offeranswer.h" -static void process_refer(SalOp *op, const belle_sip_request_event_t *event); static void sdp_process(SalOp *h){ ms_message("Doing SDP offer/answer process of type %s",h->sdp_offering ? "outgoing" : "incoming"); @@ -370,7 +369,9 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t resp=belle_sip_response_create_from_request(req,200); belle_sip_server_transaction_send_response(server_transaction,resp); }else if (strcmp("REFER",belle_sip_request_get_method(req))==0) { - process_refer(op,event); + sal_op_process_refer(op,event); + } else if (strcmp("NOTIFY",belle_sip_request_get_method(req))==0) { + sal_op_call_process_notify(op,event); } else{ ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); unsupported_method(server_transaction,req); @@ -628,91 +629,6 @@ int sal_call_is_offerer(const SalOp *h){ return h->sdp_offering; } - -/*call transfer*/ -static void sal_op_set_replaces(SalOp* op,belle_sip_header_replaces_t* replaces) { - if (op->replaces){ - belle_sip_object_unref(op->replaces); - } - op->replaces=replaces; - belle_sip_object_ref(op->replaces); -} -static void sal_op_set_referred_by(SalOp* op,belle_sip_header_referred_by_t* referred_by) { - if (op->referred_by){ - belle_sip_object_unref(op->referred_by); - } - op->referred_by=referred_by; - belle_sip_object_ref(op->referred_by); -} - -int sal_call_refer(SalOp *op, const char *refer_to){ - belle_sip_header_refer_to_t* refer_to_header=belle_sip_header_refer_to_create(belle_sip_header_address_parse(refer_to)); - belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"REFER"):NULL; /*cannot create request if dialog not set yet*/ - if (!req) { - ms_error("Cannot refer to [%s] for op [%p]",refer_to,op); - return -1; - } - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(refer_to_header)); - return sal_op_send_request(op,req); -} -int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ - ms_fatal("sal_call_refer_with_replaces not implemented yet"); - return -1; -} -int sal_call_accept_refer(SalOp *h){ - ms_fatal("sal_call_accept_refer not implemented yet"); - return -1; -} -/*informs this call is consecutive to an incoming refer */ -int sal_call_set_referer(SalOp *h, SalOp *refered_call){ - if (refered_call->replaces) - sal_op_set_replaces(h,refered_call->replaces); - if (refered_call->referred_by) - sal_op_set_referred_by(h,refered_call->referred_by); - return 0; -} -/* returns the SalOp of a call that should be replaced by h, if any */ -SalOp *sal_call_get_replaces(SalOp *h){ - if (h!=NULL && h->replaces!=NULL){ - ms_fatal("sal_call_get_replaces not implemented yet"); - } - 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"); - 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_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); - - return sal_op_send_request(op,notify); -} - -int sal_call_notify_refer_state(SalOp *op, SalOp *newcall){ - 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; - } - return 0; -} - void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){ ms_warning("sal_expire_old_registration_contacts not implemented "); } @@ -722,35 +638,3 @@ void sal_use_dates(Sal *ctx, bool_t enabled){ } - -static void process_refer(SalOp *op, const belle_sip_request_event_t *event){ - belle_sip_request_t* req = belle_sip_request_event_get_request(event); - belle_sip_header_refer_to_t *refer_to= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_refer_to_t);; - belle_sip_header_referred_by_t *referred_by= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_referred_by_t);; - belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); - belle_sip_response_t* resp; - belle_sip_uri_t* refer_to_uri; - char* refer_to_uri_str; - ms_message("Receiving REFER request on op [%p]",op); - if (refer_to) { - refer_to_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)); - - if (refer_to_uri && belle_sip_uri_get_header(refer_to_uri,"Replaces")) { - sal_op_set_replaces(op,belle_sip_header_replaces_create2(belle_sip_uri_get_header(refer_to_uri,"Replaces"))); - } - if (referred_by){ - sal_op_set_referred_by(op,referred_by); - } - refer_to_uri_str=belle_sip_uri_to_string(refer_to_uri); - resp = belle_sip_response_create_from_request(req,202); - belle_sip_server_transaction_send_response(server_transaction,resp); - op->base.root->callbacks.refer_received(op->base.root,op,refer_to_uri_str); - belle_sip_free(refer_to_uri_str); - } else { - ms_warning("cannot do anything with the refer without destination\n"); - resp = belle_sip_response_create_from_request(req,501); - belle_sip_server_transaction_send_response(server_transaction,resp); - } - -} - diff --git a/coreapi/bellesip_sal/sal_op_call_transfer.c b/coreapi/bellesip_sal/sal_op_call_transfer.c new file mode 100644 index 000000000..be1b6bc3d --- /dev/null +++ b/coreapi/bellesip_sal/sal_op_call_transfer.c @@ -0,0 +1,181 @@ +/* +linphone +Copyright (C) 2012 Belledonne Communications, Grenoble, France + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ +#include "sal_impl.h" +#include "offeranswer.h" + + + +/*call transfer*/ +static void sal_op_set_replaces(SalOp* op,belle_sip_header_replaces_t* replaces) { + if (op->replaces){ + belle_sip_object_unref(op->replaces); + } + op->replaces=replaces; + belle_sip_object_ref(op->replaces); +} +static void sal_op_set_referred_by(SalOp* op,belle_sip_header_referred_by_t* referred_by) { + if (op->referred_by){ + belle_sip_object_unref(op->referred_by); + } + op->referred_by=referred_by; + belle_sip_object_ref(op->referred_by); +} + +int sal_call_refer(SalOp *op, const char *refer_to){ + belle_sip_header_refer_to_t* refer_to_header=belle_sip_header_refer_to_create(belle_sip_header_address_parse(refer_to)); + belle_sip_request_t* req=op->dialog?belle_sip_dialog_create_request(op->dialog,"REFER"):NULL; /*cannot create request if dialog not set yet*/ + if (!req) { + ms_error("Cannot refer to [%s] for op [%p]",refer_to,op); + return -1; + } + belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(refer_to_header)); + return sal_op_send_request(op,req); +} +int sal_call_refer_with_replaces(SalOp *h, SalOp *other_call_h){ + ms_fatal("sal_call_refer_with_replaces not implemented yet"); + return -1; +} +int sal_call_accept_refer(SalOp *h){ + ms_fatal("sal_call_accept_refer not implemented yet"); + return -1; +} +/*informs this call is consecutive to an incoming refer */ +int sal_call_set_referer(SalOp *h, SalOp *refered_call){ + if (refered_call->replaces) + sal_op_set_replaces(h,refered_call->replaces); + if (refered_call->referred_by) + sal_op_set_referred_by(h,refered_call->referred_by); + return 0; +} +/* returns the SalOp of a call that should be replaced by h, if any */ +SalOp *sal_call_get_replaces(SalOp *h){ + if (h!=NULL && h->replaces!=NULL){ + ms_fatal("sal_call_get_replaces not implemented yet"); + } + 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"); + 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_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); + + return sal_op_send_request(op,notify); +} + +int sal_call_notify_refer_state(SalOp *op, SalOp *newcall){ + 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; + } + return 0; +} + + +void sal_op_process_refer(SalOp *op, const belle_sip_request_event_t *event){ + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + belle_sip_header_refer_to_t *refer_to= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_refer_to_t);; + belle_sip_header_referred_by_t *referred_by= belle_sip_message_get_header_by_type(BELLE_SIP_MESSAGE(req),belle_sip_header_referred_by_t);; + belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,req); + belle_sip_response_t* resp; + belle_sip_uri_t* refer_to_uri; + char* refer_to_uri_str; + ms_message("Receiving REFER request on op [%p]",op); + if (refer_to) { + refer_to_uri=belle_sip_header_address_get_uri(BELLE_SIP_HEADER_ADDRESS(refer_to)); + + if (refer_to_uri && belle_sip_uri_get_header(refer_to_uri,"Replaces")) { + sal_op_set_replaces(op,belle_sip_header_replaces_create2(belle_sip_uri_get_header(refer_to_uri,"Replaces"))); + } + if (referred_by){ + sal_op_set_referred_by(op,referred_by); + } + refer_to_uri_str=belle_sip_uri_to_string(refer_to_uri); + resp = belle_sip_response_create_from_request(req,202); + belle_sip_server_transaction_send_response(server_transaction,resp); + op->base.root->callbacks.refer_received(op->base.root,op,refer_to_uri_str); + belle_sip_free(refer_to_uri_str); + } else { + ms_warning("cannot do anything with the refer without destination\n"); + resp = belle_sip_response_create_from_request(req,501); + belle_sip_server_transaction_send_response(server_transaction,resp); + } + +} + +void sal_op_call_process_notify(SalOp *op, const belle_sip_request_event_t *event){ + + belle_sip_server_transaction_t* server_transaction = belle_sip_provider_create_server_transaction(op->base.root->prov,belle_sip_request_event_get_request(event)); + belle_sip_request_t* req = belle_sip_request_event_get_request(event); + const char* body = belle_sip_message_get_body(BELLE_SIP_MESSAGE(req)); + belle_sip_header_t* header_event=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Event"); + belle_sip_header_content_type_t* content_type = belle_sip_message_get_header_by_type(req,belle_sip_header_content_type_t); + belle_sip_response_t* resp; + + ms_message("Receiving NOTIFY request on op [%p]",op); + if (header_event + && strcasecmp(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(header_event)),"refer")==0 + && content_type + && strcmp(belle_sip_header_content_type_get_type(content_type),"message")==0 + && strcmp(belle_sip_header_content_type_get_subtype(content_type),"sipfrag")==0 + && body){ + belle_sip_response_t* sipfrag=BELLE_SIP_RESPONSE(belle_sip_message_parse(body)); + + if (sipfrag){ + + int code=belle_sip_response_get_status_code(sipfrag); + SalReferStatus status; + if (code==100){ + status=SalReferTrying; + }else if (code==200){ + status=SalReferSuccess; + }else if (code>=400){ + status=SalReferFailed; + } + belle_sip_object_unref(sipfrag); + resp = belle_sip_response_create_from_request(req,200); + belle_sip_server_transaction_send_response(server_transaction,resp); + op->base.root->callbacks.notify_refer(op,status); + } + }else{ + ms_error("Notify without sipfrag, trashing"); + resp = belle_sip_response_create_from_request(req,501); + belle_sip_server_transaction_send_response(server_transaction,resp); + } + +} + diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 31b945acb..1ec0bd810 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -2335,6 +2335,9 @@ LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call) { void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState state) { if (state != call->transfer_state) { LinphoneCore* lc = call->core; + ms_message("Transfer state for call [%p] changed from [%s] to [%s]",call + ,linphone_call_state_to_string(call->transfer_state) + ,linphone_call_state_to_string(call->state)); call->transfer_state = state; if (lc->vtable.transfer_state_changed) lc->vtable.transfer_state_changed(lc, call, state); diff --git a/tester/call_tester.c b/tester/call_tester.c index b44b17ad6..455be9bdd 100644 --- a/tester/call_tester.c +++ b/tester/call_tester.c @@ -60,7 +60,21 @@ void call_state_changed(LinphoneCore *lc, LinphoneCall *call, LinphoneCallState CU_FAIL("unexpected event");break; } } +void linphone_transfer_state_changed(LinphoneCore *lc, LinphoneCall *transfered, LinphoneCallState new_call_state) { + char* to=linphone_address_as_string(linphone_call_get_call_log(transfered)->to); + char* from=linphone_address_as_string(linphone_call_get_call_log(transfered)->from); + ms_message("Transferred call from [%s] to [%s], new state is [%s]",from,to,linphone_call_state_to_string(new_call_state)); + ms_free(to); + ms_free(from); + + stats* counters = (stats*)linphone_core_get_user_data(lc); + switch (cstate) { + case LinphoneCallOutgoingInit :counters->number_of_LinphoneTransferCallOutgoingInit++;break; + default: + CU_FAIL("unexpected event");break; + } +} static void linphone_call_cb(LinphoneCall *call,void * user_data) { char* to=linphone_address_as_string(linphone_call_get_call_log(call)->to); char* from=linphone_address_as_string(linphone_call_get_call_log(call)->from); @@ -466,7 +480,8 @@ static void simple_call_transfer() { /*marie calling laure*/ CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,1,2000)); - CU_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingProgress,2,2000)); + CU_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneTransferCallOutgoingInit,1,2000)); + /* initial_marie_stat=marie->stat; diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 7a1c8f133..ebbafc7d1 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -158,6 +158,7 @@ LinphoneCoreManager* linphone_core_manager_new(const char* rc_file) { mgr->v_table.message_received=message_received; mgr->v_table.new_subscription_request=new_subscribtion_request; mgr->v_table.notify_presence_recv=notify_presence_received; + mgr->v_table.transfer_state_changed=linphone_transfer_state_changed; mgr->lc=configure_lc_from(&mgr->v_table,rc_file,1); enable_codec(mgr->lc,"PCMU",8000); linphone_core_set_user_data(mgr->lc,&mgr->stat); @@ -198,6 +199,7 @@ CU_pSuite pSuite = CU_add_suite("Setup", init, uninit); } int main (int argc, char *argv[]) { int i; + char *test_name=NULL; char *suite_name=NULL; for(i=1;i