diff --git a/.cproject b/.cproject index beb21f7cb..da5a8e1df 100644 --- a/.cproject +++ b/.cproject @@ -56,7 +56,7 @@ - + @@ -77,8 +77,13 @@ - - + + + + + + + diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index f981afaa2..cb22d53f9 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -276,7 +276,7 @@ Sal * sal_init(){ sal->listener_callbacks.process_transaction_terminated=process_transaction_terminated; sal->listener_callbacks.process_auth_requested=process_auth_requested; belle_sip_provider_add_sip_listener(sal->prov,listener=belle_sip_listener_create_from_callbacks(&sal->listener_callbacks,sal)); - belle_sip_object_unref(listener); + /* belle_sip_callbacks_t is unowned, why ?belle_sip_object_unref(listener);*/ return sal; } void sal_set_user_pointer(Sal *sal, void *user_data){ diff --git a/coreapi/bellesip_sal/sal_impl.h b/coreapi/bellesip_sal/sal_impl.h index 695799d09..069b3934a 100644 --- a/coreapi/bellesip_sal/sal_impl.h +++ b/coreapi/bellesip_sal/sal_impl.h @@ -76,7 +76,7 @@ belle_sip_request_t* sal_op_build_request(SalOp *op,const char* method); void sal_op_call_fill_cbs(SalOp*op); void sal_op_set_remote_ua(SalOp*op,belle_sip_message_t* message); -void sal_op_send_request(SalOp* op, belle_sip_request_t* request); +int sal_op_send_request(SalOp* op, belle_sip_request_t* request); void sal_op_resend_request(SalOp* op, belle_sip_request_t* request); void sal_process_authentication(SalOp *op, belle_sip_response_t *response); diff --git a/coreapi/bellesip_sal/sal_op_call.c b/coreapi/bellesip_sal/sal_op_call.c index 94c9b4d94..91006ae0d 100644 --- a/coreapi/bellesip_sal/sal_op_call.c +++ b/coreapi/bellesip_sal/sal_op_call.c @@ -194,8 +194,9 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t } case BELLE_SIP_DIALOG_CONFIRMED: { switch (op->state) { - case SalOpStateEarly: - handle_sdp_from_response(op,response); + case SalOpStateEarly:/*invite case*/ + case SalOpStateActive: /*re-invite case*/ + handle_sdp_from_response(op,response); ack=belle_sip_dialog_create_ack(op->dialog,belle_sip_dialog_get_local_seq_number(op->dialog)); if (ack==NULL) { ms_error("This call has been already terminated."); @@ -207,9 +208,10 @@ static void call_response_event(void *op_base, const belle_sip_response_event_t op->sdp_answer=NULL; } belle_sip_dialog_send_ack(op->dialog,ack); + op->state=SalOpStateActive; op->base.root->callbacks.call_accepted(op); break; - case SalOpStateActive: + case SalOpStateTerminated: default: ms_error("op [%p] receive answer [%i] not implemented",op,code); @@ -246,17 +248,27 @@ static void unsupported_method(belle_sip_server_transaction_t* server_transactio return; } +static void process_sdp_for_invite(SalOp* op,belle_sip_request_t* invite) { + belle_sdp_session_description_t* sdp; + if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(invite)))) { + op->sdp_offering=FALSE; + op->base.remote_media=sal_media_description_new(); + sdp_to_media_description(sdp,op->base.remote_media); + belle_sip_object_unref(sdp); + }else + op->sdp_offering=TRUE; +} static void process_request_event(void *op_base, const belle_sip_request_event_t *event) { SalOp* op = (SalOp*)op_base; 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_object_ref(server_transaction); if (op->pending_server_trans) belle_sip_object_unref(op->pending_server_trans); op->pending_server_trans=server_transaction; - + belle_sdp_session_description_t* sdp; belle_sip_request_t* req = belle_sip_request_event_get_request(event); belle_sip_header_t* replace_header; belle_sip_dialog_state_t dialog_state; - belle_sdp_session_description_t* sdp; + belle_sip_header_t* call_info; if (!op->dialog) { @@ -274,13 +286,8 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t } else if(op->replaces) { ms_warning("replace header already set"); } - if ((sdp=belle_sdp_session_description_create(BELLE_SIP_MESSAGE(req)))) { - op->sdp_offering=FALSE; - op->base.remote_media=sal_media_description_new(); - sdp_to_media_description(sdp,op->base.remote_media); - belle_sip_object_unref(sdp); - }else - op->sdp_offering=TRUE; + + process_sdp_for_invite(op,req); if ((call_info=belle_sip_message_get_header(BELLE_SIP_MESSAGE(req),"Call-Info"))) { if( strstr(belle_sip_header_extension_get_value(BELLE_SIP_HEADER_EXTENSION(call_info)),"answer-after=") != NULL) { @@ -337,6 +344,19 @@ static void process_request_event(void *op_base, const belle_sip_request_event_t op->base.root->callbacks.call_ack(op); } else if(strcmp("BYE",belle_sip_request_get_method(req))==0) { call_terminated(op,server_transaction,belle_sip_request_event_get_request(event),200); + } else if(strcmp("INVITE",belle_sip_request_get_method(req))==0) { + /*re-invite*/ + if (op->base.remote_media){ + sal_media_description_unref(op->base.remote_media); + op->base.remote_media=NULL; + } + if (op->result){ + sal_media_description_unref(op->result); + op->result=NULL; + } + process_sdp_for_invite(op,req); + + op->base.root->callbacks.call_updating(op); } else { ms_error("unexpected method [%s] for dialog [%p]",belle_sip_request_get_method(req),op->dialog); } @@ -359,9 +379,24 @@ int sal_call_set_local_media_description(SalOp *op, SalMediaDescription *desc){ op->base.local_media=desc; return 0; } +static void sal_op_fill_invite(SalOp *op, belle_sip_request_t* invite) { + belle_sip_header_allow_t* header_allow; + header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),BELLE_SIP_HEADER(header_allow)); + + if (op->base.root->session_expires!=0){ + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Session-expires", "200")); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(invite),belle_sip_header_create( "Supported", "timer")); + } + if (op->base.local_media){ + op->sdp_offering=TRUE; + set_sdp_from_desc(BELLE_SIP_MESSAGE(invite),op->base.local_media); + }else op->sdp_offering=FALSE; + return; +} int sal_call(SalOp *op, const char *from, const char *to){ belle_sip_request_t* req; - belle_sip_header_allow_t* header_allow; + /* belle_sip_client_transaction_t* client_transaction; belle_sip_provider_t* prov=op->base.root->prov; belle_sip_header_route_t* route_header;*/ @@ -370,22 +405,9 @@ int sal_call(SalOp *op, const char *from, const char *to){ sal_op_set_to(op,to); req=sal_op_build_request(op,"INVITE"); - header_allow = belle_sip_header_allow_create("INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO"); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(header_allow)); - if (op->base.root->session_expires!=0){ - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create( "Session-expires", "200")); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),belle_sip_header_create( "Supported", "timer")); - } - if (op->base.local_media){ - op->sdp_offering=TRUE; - set_sdp_from_desc(BELLE_SIP_MESSAGE(req),op->base.local_media); - }else op->sdp_offering=FALSE; + sal_op_fill_invite(op,req); -/* if (sal_op_get_route_address(op)) { - route_header = belle_sip_header_route_create(BELLE_SIP_HEADER_ADDRESS(sal_op_get_route_address(op))); - belle_sip_message_add_header(BELLE_SIP_MESSAGE(req),BELLE_SIP_HEADER(route_header)); - }*/ sal_op_call_fill_cbs(op); sal_op_send_request(op,req); /*op->pending_inv_client_trans = client_transaction = belle_sip_provider_create_client_transaction(prov,req); @@ -499,13 +521,14 @@ int sal_call_decline(SalOp *op, SalReason reason, const char *redirection /*opti return 0; } -int sal_call_update(SalOp *h, const char *subject){ - ms_fatal("sal_call_update not implemented yet"); - return -1; +int sal_call_update(SalOp *op, const char *subject){ + belle_sip_request_t *reinvite=belle_sip_dialog_create_request(op->dialog,"INVITE"); + belle_sip_message_add_header(BELLE_SIP_MESSAGE(reinvite),belle_sip_header_create( "Subject", subject)); + sal_op_fill_invite(op, reinvite); + return sal_op_send_request(op,reinvite); } SalMediaDescription * sal_call_get_remote_media_description(SalOp *h){ - ms_fatal("sal_call_get_remote_media_description not implemented yet"); - return NULL; + return h->base.remote_media;; } diff --git a/coreapi/bellesip_sal/sal_op_impl.c b/coreapi/bellesip_sal/sal_op_impl.c index f61ff5ab7..a178ade97 100644 --- a/coreapi/bellesip_sal/sal_op_impl.c +++ b/coreapi/bellesip_sal/sal_op_impl.c @@ -145,7 +145,7 @@ void sal_op_resend_request(SalOp* op, belle_sip_request_t* request) { belle_sip_header_cseq_set_seq_number(cseq,belle_sip_header_cseq_get_seq_number(cseq)+1); sal_op_send_request(op,request); } -void sal_op_send_request(SalOp* op, belle_sip_request_t* request) { +int sal_op_send_request(SalOp* op, belle_sip_request_t* request) { belle_sip_client_transaction_t* client_transaction; belle_sip_provider_t* prov=op->base.root->prov; belle_sip_header_route_t* route_header; @@ -168,6 +168,6 @@ void sal_op_send_request(SalOp* op, belle_sip_request_t* request) { /*hmm just in case we already have authentication param in cache*/ belle_sip_provider_add_authorization(op->base.root->prov,request,NULL); } - belle_sip_client_transaction_send_request(client_transaction); + return belle_sip_client_transaction_send_request(client_transaction); } diff --git a/coreapi/bellesip_sal/sal_sdp.c b/coreapi/bellesip_sal/sal_sdp.c index 7a2f918f1..482bab472 100644 --- a/coreapi/bellesip_sal/sal_sdp.c +++ b/coreapi/bellesip_sal/sal_sdp.c @@ -29,6 +29,7 @@ belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescrip MSList* pt_it; PayloadType* pt; char buffer[1024]; + char* dir; if (strchr(desc->addr,':')!=NULL){ inet6=1; @@ -114,6 +115,23 @@ belle_sdp_session_description_t * media_description_to_sdp(const SalMediaDescrip } } + switch(desc->streams[i].dir){ + case SalStreamSendRecv: + /*dir="sendrecv";*/ + dir=NULL; + break; + case SalStreamRecvOnly: + dir="recvonly"; + break; + case SalStreamSendOnly: + dir="sendonly"; + break; + case SalStreamInactive: + dir="inactive"; + break; + } + if (dir) belle_sdp_media_description_add_attribute(media_desc,belle_sdp_attribute_create(dir,NULL)); + belle_sdp_session_description_add_media_description(session_desc,media_desc); } diff --git a/tester/flexisip.conf b/tester/flexisip.conf index 61d55fb2f..b9d5b94a0 100755 --- a/tester/flexisip.conf +++ b/tester/flexisip.conf @@ -18,7 +18,7 @@ auto-respawn=true # List of white space separated host names pointing to this machine. # This is to prevent loops while routing SIP messages. # Default value: localhost -aliases=localhost +aliases=localhost sipopen.example.org sip.example.org # List of white space separated SIP uris where the proxy must listen.Wildcard # (*) can be used to mean 'all local ip addresses'. If 'transport' @@ -36,7 +36,7 @@ aliases=localhost # 'sip.linphone.org' used in SIP messages. Bind address won't appear: # transports=sips:sip.linphone.org:6060;maddr=192.168.0.29 # Default value: sip:* -transports=sip:* sips:* +transports=sip:192.168.56.101:5060 sips:192.168.56.101:5061 # An absolute path of a directory where TLS server certificate and # private key can be found, concatenated inside an 'agent.pem' file. @@ -128,12 +128,12 @@ enabled=true # in 'a.org b.org c.org', (to.uri.domain in 'a.org b.org c.org') # && (user-agent == 'Linphone v2') # Default value: -filter= +filter= from.uri.domain contains 'sip.example.org' # List of whitespace separated domain names to challenge. Others # are denied. # Default value: -auth-domains= auth.example.org +auth-domains= sip.example.org # List of whitespace separated IP which will not be challenged. # Default value: @@ -259,7 +259,7 @@ filter= # List of whitelist separated domain names to be managed by the # registrar. # Default value: localhost -reg-domains=localhost auth.example.org +reg-domains=localhost sip.example.org sipopen.example.org # Maximum number of registered contacts of an address of record. # Default value: 15 diff --git a/tester/liblinphone_tester.c b/tester/liblinphone_tester.c index 417319d24..def062827 100644 --- a/tester/liblinphone_tester.c +++ b/tester/liblinphone_tester.c @@ -19,8 +19,8 @@ #include "CUnit/Basic.h" #include "linphonecore.h" -const char *test_domain="sip.example.org"; -const char *auth_domain="auth.example.org"; +const char *test_domain="sipopen.example.org"; +const char *auth_domain="sip.example.org"; const char* test_username="liblinphone_tester"; const char* test_password="secret"; @@ -335,6 +335,39 @@ static void linphone_core_manager_destroy(LinphoneCoreManager* mgr) { linphone_core_destroy(mgr->lc); free(mgr); } + +static bool_t call(LinphoneCoreManager* caller_mgr,LinphoneCoreManager* callee_mgr) { + LinphoneProxyConfig* proxy; + linphone_core_get_default_proxy(callee_mgr->lc,&proxy); + CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); + LinphoneAddress* dest_identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + linphone_address_clean(dest_identity); + + CU_ASSERT_PTR_NOT_NULL_FATAL(linphone_core_invite_address(caller_mgr->lc,dest_identity)); + linphone_address_destroy(dest_identity); + /*linphone_core_invite(caller_mgr->lc,"pauline");*/ + + CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallIncomingReceived,1)); + CU_ASSERT_TRUE(linphone_core_inc_invite_pending(callee_mgr->lc)); + CU_ASSERT_EQUAL(caller_mgr->stat.number_of_LinphoneCallOutgoingProgress,1); + CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallOutgoingRinging,1)); + + linphone_core_get_default_proxy(caller_mgr->lc,&proxy); + CU_ASSERT_PTR_NOT_NULL_FATAL(proxy); + LinphoneAddress* identity = linphone_address_new(linphone_proxy_config_get_identity(proxy)); + CU_ASSERT_TRUE(linphone_address_weak_equal(identity,linphone_core_get_current_call_remote_address(callee_mgr->lc))); + linphone_address_destroy(identity); + + linphone_core_accept_call(callee_mgr->lc,linphone_core_get_current_call(callee_mgr->lc)); + + CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallConnected,1)); + CU_ASSERT_TRUE_FATAL(wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallConnected,1)); + /*just to sleep*/ + return wait_for(callee_mgr->lc,caller_mgr->lc,&caller_mgr->stat.number_of_LinphoneCallStreamsRunning,1) + && + wait_for(callee_mgr->lc,caller_mgr->lc,&callee_mgr->stat.number_of_LinphoneCallStreamsRunning,1); + +} static void simple_call() { LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); @@ -430,6 +463,67 @@ static void call_early_declined() { linphone_core_manager_destroy(marie); linphone_core_manager_destroy(pauline); } + +static void call_terminated_by_caller() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + CU_ASSERT_TRUE(call(pauline,marie)); + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_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_paused_resumed() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + LinphoneCall* call_obj; + + CU_ASSERT_TRUE(call(pauline,marie)); + call_obj = linphone_core_get_current_call(pauline->lc); + + linphone_core_pause_call(pauline->lc,call_obj); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallPaused,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallPausedByRemote,1)); + + linphone_core_resume_call(pauline->lc,call_obj); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallStreamsRunning,2)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallStreamsRunning,2)); + + /*just to sleep*/ + linphone_core_terminate_all_calls(pauline->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_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_srtp() { + LinphoneCoreManager* marie = linphone_core_manager_new("./tester/marie_rc"); + LinphoneCoreManager* pauline = linphone_core_manager_new("./tester/pauline_rc"); + + linphone_core_set_media_encryption(marie->lc,LinphoneMediaEncryptionSRTP); + linphone_core_set_media_encryption(pauline->lc,LinphoneMediaEncryptionSRTP); + + CU_ASSERT_TRUE(call(pauline,marie)); + + CU_ASSERT_EQUAL(linphone_core_get_media_encryption(marie->lc),LinphoneMediaEncryptionSRTP); + CU_ASSERT_EQUAL(linphone_core_get_media_encryption(pauline->lc),LinphoneMediaEncryptionSRTP); + + /*just to sleep*/ + linphone_core_terminate_all_calls(marie->lc); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&pauline->stat.number_of_LinphoneCallEnd,1)); + CU_ASSERT_TRUE(wait_for(pauline->lc,marie->lc,&marie->stat.number_of_LinphoneCallEnd,1)); + + linphone_core_manager_destroy(marie); + linphone_core_manager_destroy(pauline); +} + int init_test_suite () { CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); @@ -471,7 +565,15 @@ CU_pSuite pSuite = CU_add_suite("liblinphone", init, uninit); if (NULL == CU_add_test(pSuite, "simple_call", simple_call)) { return CU_get_error(); } - + if (NULL == CU_add_test(pSuite, "call_terminated_by_caller", call_terminated_by_caller)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_paused_resumed", call_paused_resumed)) { + return CU_get_error(); + } + if (NULL == CU_add_test(pSuite, "call_srtp", call_srtp)) { + return CU_get_error(); + } return 0; } int main (int argc, char *argv[]) { diff --git a/tester/marie_rc b/tester/marie_rc index 2a808a7cd..b0cb5c761 100644 --- a/tester/marie_rc +++ b/tester/marie_rc @@ -9,13 +9,13 @@ ping_with_options=0 username=marie userid=marie passwd=secret -realm="auth.example.org" +realm="sip.example.org" [proxy_0] -reg_proxy=auth.example.org;transport=tcp -reg_route=auth.example.org;transport=tcp;lr -reg_identity=sip:marie@auth.example.org +reg_proxy=sip.example.org;transport=tcp +reg_route=sip.example.org;transport=tcp;lr +reg_identity=sip:marie@sip.example.org reg_expires=3600 reg_sendregister=1 publish=0 diff --git a/tester/pauline_rc b/tester/pauline_rc index 455683cc6..cba6b564f 100644 --- a/tester/pauline_rc +++ b/tester/pauline_rc @@ -9,13 +9,13 @@ ping_with_options=0 username=pauline userid=pauline passwd=secret -realm="auth.example.org" +realm="sip.example.org" [proxy_0] -reg_proxy=auth.example.org;transport=tls -reg_route=auth.example.org;transport=tls;lr -reg_identity=sip:pauline@auth.example.org +reg_proxy=sip.example.org;transport=tls +reg_route=sip.example.org;transport=tls;lr +reg_identity=sip:pauline@sip.example.org reg_expires=3600 reg_sendregister=1 publish=0