Commit 2792e073 authored by Simon Morlat's avatar Simon Morlat
Browse files

Implement automatic BYE of orphan dialogs

parent c347156d
......@@ -462,6 +462,24 @@ int SalCallOp::vfuRetryCb (void *userCtx, unsigned int events) {
return BELLE_SIP_STOP;
}
bool SalCallOp::checkForOrphanDialogOn2xx(belle_sip_dialog_t *dialog){
if (mDialog && dialog && mDialog != dialog
&& belle_sip_dialog_get_state(mDialog) == BELLE_SIP_DIALOG_CONFIRMED
&& belle_sip_dialog_get_state(dialog) == BELLE_SIP_DIALOG_CONFIRMED){
/* we just got a 2xx response that established a new dialog, but a former one was already confirmed.
* This is a race condition. We should simply terminate this new dialog by sending ACK and BYE.*/
belle_sip_request_t * ack, *bye;
belle_sip_client_transaction_t *bye_transaction;
ack = belle_sip_dialog_create_ack(dialog, belle_sip_dialog_get_local_seq_number(dialog));
belle_sip_dialog_send_ack(dialog, ack);
bye = belle_sip_dialog_create_request(dialog,"BYE");
bye_transaction = belle_sip_provider_create_client_transaction(mRoot->mProvider, bye);
belle_sip_client_transaction_send_request(bye_transaction);
return true;
}
return false;
}
void SalCallOp::processResponseCb (void *userCtx, const belle_sip_response_event_t *event) {
auto op = static_cast<SalCallOp *>(userCtx);
auto response = belle_sip_response_event_get_response(event);
......@@ -473,6 +491,10 @@ void SalCallOp::processResponseCb (void *userCtx, const belle_sip_response_event
}
auto dialog = belle_sip_response_event_get_dialog(event);
if (op->checkForOrphanDialogOn2xx(dialog)){
/* ignored response.*/
return;
}
op->setOrUpdateDialog(dialog);
auto dialogState = dialog ? belle_sip_dialog_get_state(dialog) : BELLE_SIP_DIALOG_NULL;
lInfo() << "Op [" << op << "] receiving call response [" << code << "], dialog is [" << dialog << "] in state ["
......
......@@ -101,6 +101,7 @@ private:
void notifyLastResponse (SalCallOp *newCallOp);
void processRefer (const belle_sip_request_event_t *event, belle_sip_server_transaction_t *serverTransaction);
void processNotify (const belle_sip_request_event_t *event, belle_sip_server_transaction_t *serverTransaction);
bool checkForOrphanDialogOn2xx(belle_sip_dialog_t *dialog);
static void setAddrTo0000 (char value[], size_t sz);
static bool isMediaDescriptionAcceptable (SalMediaDescription *md);
......
......@@ -753,7 +753,7 @@ belle_sip_dialog_t *SalOp::linkOpWithDialog (belle_sip_dialog_t *dialog) {
}
void SalOp::setOrUpdateDialog (belle_sip_dialog_t *dialog) {
lInfo() << "op [" << this << "] : set_or_update_dialog() current=[" << mDialog << "] new=[" << dialog << "]";
lInfo() << "op [" << this << "] : setOrUpdateDialog() current=[" << mDialog << "] new=[" << dialog << "]";
ref();
if (mDialog != dialog) {
if (mDialog){
......
......@@ -277,6 +277,11 @@ void Sal::processResponseEventCb (void *userCtx, const belle_sip_response_event_
}
auto op = static_cast<SalOp *>(belle_sip_transaction_get_application_data(BELLE_SIP_TRANSACTION(clientTransaction)));
if (!op){
/* This happens when receiving a 200 OK for an orphan dialog that has been BYEd.*/
lInfo() << "No Op related with this response.";
return;
}
if (op->mState == SalOp::State::Terminated) {
lInfo() << "Op [" << op << "] is terminated, nothing to do with this [" << responseCode << "]";
return;
......
......@@ -584,7 +584,6 @@ static void call_outbound_using_different_proxies(void) {
linphone_core_manager_destroy(pauline);
}
#if 0 /* TODO: activate test when the implementation is ready */
static void multiple_answers_call(void) {
/* Scenario is this: pauline calls marie, which is registered 2 times.
Both linphones answer at the same time, and only one should get the
......@@ -599,41 +598,46 @@ static void multiple_answers_call(void) {
lcs = bctbx_list_append(lcs,marie1->lc);
lcs = bctbx_list_append(lcs,marie2->lc);
BC_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 1, 2000));
BC_ASSERT_PTR_NOT_NULL( linphone_core_invite_address(pauline->lc, marie1->identity ) );
BC_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallIncomingReceived, 1, 2000));
BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived, 1, 2000));
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress, 1, 2000));
BC_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallIncomingReceived, 1, 10000));
BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived, 1, 10000));
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress, 1, 5000));
// marie 1 and 2 answer at the same time
call1 = linphone_core_get_current_call(marie1->lc);
call2 = linphone_core_get_current_call(marie2->lc);
BC_ASSERT_PTR_NOT_NULL_FATAL(call1);
BC_ASSERT_PTR_NOT_NULL_FATAL(call2);
if (BC_ASSERT_PTR_NOT_NULL(call1) && BC_ASSERT_PTR_NOT_NULL(call2)) {
BC_ASSERT_EQUAL( linphone_call_accept(call1), 0, int, "%d");
ms_sleep(1); /*sleep to make sure that the 200OK of marie1 reaches the server first*/
BC_ASSERT_EQUAL( linphone_call_accept(call2), 0, int, "%d");
BC_ASSERT_EQUAL( linphone_core_accept_call(marie1->lc, call1), 0, int, "%d");
BC_ASSERT_EQUAL( linphone_core_accept_call(marie2->lc, call2), 0, int, "%d");
BC_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 10000) );
BC_ASSERT_TRUE( wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallStreamsRunning, 1, 10000) );
/*Pauline will send a bye to marie2, as its 200Ok arrived second*/
BC_ASSERT_TRUE( wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallEnd, 1, 10000) );
BC_ASSERT_TRUE( wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallReleased, 1, 10000) );
BC_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) );
BC_ASSERT_TRUE( wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) );
BC_ASSERT_TRUE( wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallEnd, 1, 2000) );
liblinphone_tester_check_rtcp(pauline, marie1);
end_call(marie1, pauline);
}
linphone_core_manager_destroy(pauline);
linphone_core_manager_destroy(marie1);
linphone_core_manager_destroy(marie2);
bctbx_list_free(lcs);
}
#endif
static void multiple_answers_call_with_media_relay(void) {
/* Scenario is this: pauline calls marie, which is registered 2 times.
* Both linphones answer at the same time, and only one should get the
* call running, the other should be terminated */
* call running, the other should be terminated.
* In this test, the server is expected to send ACK-BYE, unlike in multiple_answers_call()*/
LinphoneCoreManager* pauline = linphone_core_manager_new2( "pauline_tcp_rc", FALSE);
LinphoneCoreManager* marie1 = linphone_core_manager_new2( "marie_rc", FALSE);
LinphoneCoreManager* marie2 = linphone_core_manager_new2( "marie_rc", FALSE );
......@@ -660,12 +664,11 @@ static void multiple_answers_call_with_media_relay(void) {
linphone_core_set_user_agent(marie1->lc, "Natted Linphone", NULL);
linphone_core_set_user_agent(marie2->lc, "Natted Linphone", NULL);
BC_ASSERT_TRUE(wait_for_until(pauline->lc, NULL, &pauline->stat.number_of_LinphoneRegistrationOk, 1, 2000));
BC_ASSERT_PTR_NOT_NULL( linphone_core_invite_address(pauline->lc, marie1->identity ) );
BC_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallIncomingReceived, 1, 2000));
BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived, 1, 2000));
BC_ASSERT_TRUE(wait_for_list(lcs,&marie1->stat.number_of_LinphoneCallIncomingReceived, 1, 10000));
BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived, 1, 10000));
BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingProgress, 1, 2000));
// marie 1 and 2 answer at the same time
......@@ -677,10 +680,10 @@ static void multiple_answers_call_with_media_relay(void) {
ms_sleep(1); /*sleep to make sure that the 200OK of marie1 reaches the server first*/
BC_ASSERT_EQUAL( linphone_call_accept(call2), 0, int, "%d");
BC_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) );
BC_ASSERT_TRUE( wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallStreamsRunning, 1, 2000) );
BC_ASSERT_TRUE( wait_for_list(lcs, &pauline->stat.number_of_LinphoneCallStreamsRunning, 1, 10000) );
BC_ASSERT_TRUE( wait_for_list(lcs, &marie1->stat.number_of_LinphoneCallStreamsRunning, 1, 10000) );
/*the server will send a bye to marie2, as is 200Ok arrived second*/
BC_ASSERT_TRUE( wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallEnd, 1, 4000) );
BC_ASSERT_TRUE( wait_for_list(lcs, &marie2->stat.number_of_LinphoneCallEnd, 1, 10000) );
end_call(marie1, pauline);
}
......@@ -5264,9 +5267,7 @@ test_t call_tests[] = {
TEST_NO_TAG("Outbound call with multiple proxy possible", call_outbound_with_multiple_proxy),
TEST_NO_TAG("Outbound call using different proxies", call_outbound_using_different_proxies),
TEST_NO_TAG("Audio call recording", audio_call_recording_test),
#if 0 // not yet activated because not implemented
TEST_NO_TAG("Multiple answers to a call", multiple_answers_call),
#endif
TEST_NO_TAG("Multiple answers to a call with media relay", multiple_answers_call_with_media_relay),
TEST_NO_TAG("Call with media relay", call_with_media_relay),
TEST_NO_TAG("Call with media relay (random ports)", call_with_media_relay_random_ports),
......
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