Fixes #34 in public release. We now have different states for the MTDCanceling and canceled calls now end in a canceled state. Also a few other hardening bug fixes.

git-svn-id: http://wush.net/svn/range/software/public/openbts/trunk@3018 19bc5d8c-e614-43d4-8b26-e1612bc8e597
This commit is contained in:
kurtis.heimerl
2012-01-10 22:57:53 +00:00
parent e67a296a62
commit 64656ed5b5
6 changed files with 118 additions and 29 deletions

View File

@@ -118,7 +118,8 @@ void forceSIPClearing(TransactionEntry *transaction)
{ {
SIP::SIPState state = transaction->SIPState(); SIP::SIPState state = transaction->SIPState();
LOG(INFO) << "SIP state " << state; LOG(INFO) << "SIP state " << state;
if (state==SIP::Cleared) return; //why aren't we checking for failed here? -kurtis
if (transaction->SIPFinished()) return;
if (state==SIP::Active){ if (state==SIP::Active){
//Changes state to clearing //Changes state to clearing
transaction->MODSendBYE(); transaction->MODSendBYE();
@@ -325,7 +326,7 @@ bool callManagementDispatchGSM(TransactionEntry *transaction, GSM::LogicalChanne
LCH->send(GSM::L3ReleaseComplete(transaction->L3TI())); LCH->send(GSM::L3ReleaseComplete(transaction->L3TI()));
LCH->send(GSM::L3ChannelRelease()); LCH->send(GSM::L3ChannelRelease());
transaction->GSMState(GSM::NullState); transaction->GSMState(GSM::NullState);
transaction->MTDSendOK(); transaction->MTDSendBYEOK();
return true; return true;
} }
@@ -514,10 +515,9 @@ bool updateSIPSignalling(TransactionEntry *transaction, GSM::LogicalChannel *LCH
// The main purpose of this code is to initiate disconnects from the SIP side. // The main purpose of this code is to initiate disconnects from the SIP side.
if (transaction->SIPState()==SIP::Cleared) return true; if (transaction->SIPFinished()) return true;
bool GSMClearedOrClearing = GSMCleared || transaction->clearingGSM(); bool GSMClearedOrClearing = GSMCleared || transaction->clearingGSM();
if (transaction->MTDCheckBYE() == SIP::MTDClearing) { if (transaction->MTDCheckBYE() == SIP::MTDClearing) {
LOG(DEBUG) << "got SIP BYE " << *transaction; LOG(DEBUG) << "got SIP BYE " << *transaction;
if (!GSMClearedOrClearing) { if (!GSMClearedOrClearing) {
@@ -528,11 +528,11 @@ bool updateSIPSignalling(TransactionEntry *transaction, GSM::LogicalChannel *LCH
} else { } else {
// GSM already cleared? // GSM already cleared?
// Ack the BYE and end the call. // Ack the BYE and end the call.
transaction->MTDSendOK(); transaction->MTDSendBYEOK();
} }
} }
return transaction->SIPState()==SIP::Cleared; return (transaction->SIPFinished());
} }
@@ -548,8 +548,8 @@ bool updateSignalling(TransactionEntry *transaction, GSM::LogicalChannel *LCH, u
{ {
bool GSMCleared = (updateGSMSignalling(transaction,LCH,timeout)); bool GSMCleared = (updateGSMSignalling(transaction,LCH,timeout));
bool SIPCleared = updateSIPSignalling(transaction,LCH,GSMCleared); bool SIPFinished = updateSIPSignalling(transaction,LCH,GSMCleared);
return GSMCleared && SIPCleared; return GSMCleared && SIPFinished;
} }
@@ -628,7 +628,7 @@ bool waitInCall(TransactionEntry *transaction, GSM::TCHFACCHLogicalChannel *TCH,
void callManagementLoop(TransactionEntry *transaction, GSM::TCHFACCHLogicalChannel* TCH) void callManagementLoop(TransactionEntry *transaction, GSM::TCHFACCHLogicalChannel* TCH)
{ {
LOG(INFO) << " call connected " << *transaction; LOG(INFO) << " call connected " << *transaction;
// poll everything until the call is cleared // poll everything until the call is finished
while (!pollInCall(transaction,TCH)) { } while (!pollInCall(transaction,TCH)) { }
gTransactionTable.remove(transaction); gTransactionTable.remove(transaction);
} }
@@ -948,11 +948,17 @@ void Control::MTCStarter(TransactionEntry *transaction, GSM::LogicalChannel *LCH
return; return;
} }
// Check for SIP cancel, too. // Check for SIP cancel, too.
if (transaction->MTCCheckForCancel()==SIP::Fail) { if (transaction->MTCCheckForCancel()==SIP::MTDCanceling) {
LOG(NOTICE) << "call cancelled or failed on SIP side"; LOG(INFO) << "call cancelled on SIP side";
transaction->MTDSendCANCELOK();
// Cause 0x15 is "rejected" // Cause 0x15 is "rejected"
return abortAndRemoveCall(transaction,LCH,GSM::L3Cause(0x15)); return abortAndRemoveCall(transaction,LCH,GSM::L3Cause(0x15));
} }
//lastly check if we're toast
if(transaction->SIPState()==SIP::Fail) {
LOG(DEBUG) << "Call failed";
return abortAndRemoveCall(transaction,LCH,GSM::L3Cause(0x7F));
}
} }
// The transaction is moving to the MTCController. // The transaction is moving to the MTCController.
@@ -1006,8 +1012,15 @@ void Control::MTCController(TransactionEntry *transaction, GSM::TCHFACCHLogicalC
transaction->MTCSendRinging(); transaction->MTCSendRinging();
} }
// Check for SIP cancel, too. // Check for SIP cancel, too.
if (transaction->MTCCheckForCancel()==SIP::Fail) { if (transaction->MTCCheckForCancel()==SIP::MTDCanceling) {
LOG(DEBUG) << "MTCCheckForCancel return Fail"; LOG(INFO) << "MTCCheckForCancel return Canceling";
transaction->MTDSendCANCELOK();
// Cause 0x15 is "rejected"
return abortAndRemoveCall(transaction,TCH,GSM::L3Cause(0x15));
}
//check if we're toast
if (transaction->SIPState()==SIP::Fail){
LOG(DEBUG) << "Call failed";
return abortAndRemoveCall(transaction,TCH,GSM::L3Cause(0x7F)); return abortAndRemoveCall(transaction,TCH,GSM::L3Cause(0x7F));
} }
} }
@@ -1031,6 +1044,10 @@ void Control::MTCController(TransactionEntry *transaction, GSM::TCHFACCHLogicalC
break; break;
case SIP::Connecting: case SIP::Connecting:
break; break;
case SIP::MTDCanceling:
state = transaction->MTDSendCANCELOK();
// Cause 0x15 is "rejected"
return abortAndRemoveCall(transaction,TCH,GSM::L3Cause(0x15));
default: default:
LOG(NOTICE) << "SIP unexpected state " << state; LOG(NOTICE) << "SIP unexpected state " << state;
break; break;

View File

@@ -460,10 +460,18 @@ SIP::SIPState TransactionEntry::MTDCheckBYE()
return state; return state;
} }
SIP::SIPState TransactionEntry::MTDSendOK() SIP::SIPState TransactionEntry::MTDSendBYEOK()
{ {
ScopedLock lock(mLock); ScopedLock lock(mLock);
SIP::SIPState state = mSIP.MTDSendOK(); SIP::SIPState state = mSIP.MTDSendBYEOK();
echoSIPState(state);
return state;
}
SIP::SIPState TransactionEntry::MTDSendCANCELOK()
{
ScopedLock lock(mLock);
SIP::SIPState state = mSIP.MTDSendCANCELOK();
echoSIPState(state); echoSIPState(state);
return state; return state;
} }

View File

@@ -177,6 +177,8 @@ class TransactionEntry {
SIP::SIPState SIPState() { ScopedLock lock(mLock); return mSIP.state(); } SIP::SIPState SIPState() { ScopedLock lock(mLock); return mSIP.state(); }
bool SIPFinished() { ScopedLock lock(mLock); return mSIP.finished(); }
SIP::SIPState MOCSendINVITE(const char* calledUser, const char* calledDomain, short rtpPort, unsigned codec); SIP::SIPState MOCSendINVITE(const char* calledUser, const char* calledDomain, short rtpPort, unsigned codec);
SIP::SIPState MOCResendINVITE(); SIP::SIPState MOCResendINVITE();
SIP::SIPState MOCWaitForOK(); SIP::SIPState MOCWaitForOK();
@@ -204,7 +206,8 @@ class TransactionEntry {
SIP::SIPState MODWaitForOK(); SIP::SIPState MODWaitForOK();
SIP::SIPState MTDCheckBYE(); SIP::SIPState MTDCheckBYE();
SIP::SIPState MTDSendOK(); SIP::SIPState MTDSendBYEOK();
SIP::SIPState MTDSendCANCELOK();
// TODO: Remove contentType from here and use the setter above. // TODO: Remove contentType from here and use the setter above.
SIP::SIPState MOSMSSendMESSAGE(const char* calledUser, const char* calledDomain, const char* contentType); SIP::SIPState MOSMSSendMESSAGE(const char* calledUser, const char* calledDomain, const char* contentType);

View File

@@ -71,6 +71,8 @@ const char* SIP::SIPStateString(SIPState s)
case MODClearing: return "MODClearing"; case MODClearing: return "MODClearing";
case MODCanceling: return "MODCanceling"; case MODCanceling: return "MODCanceling";
case MTDClearing: return "MTDClearing"; case MTDClearing: return "MTDClearing";
case MTDCanceling: return "MTDCanceling";
case Canceled: return "Canceled";
case Cleared: return "Cleared"; case Cleared: return "Cleared";
case MessageSubmit: return "SMS-Submit"; case MessageSubmit: return "SMS-Submit";
default: return NULL; default: return NULL;
@@ -622,8 +624,12 @@ SIPState SIPEngine::MODWaitForOK()
if (!responded) { LOG(ALERT) << "lost contact with proxy " << mProxyIP << ":" << mProxyPort; } if (!responded) { LOG(ALERT) << "lost contact with proxy " << mProxyIP << ":" << mProxyPort; }
// However we got here, the SIP side of the call is cleared now. //Canceled if we're canceling, otherwise clear
if (mState==MODCanceling){
mState = Canceled;
} else {
mState = Cleared; mState = Cleared;
}
return mState; return mState;
} }
@@ -669,7 +675,7 @@ SIPState SIPEngine::MTDCheckBYE()
} }
SIPState SIPEngine::MTDSendOK() SIPState SIPEngine::MTDSendBYEOK()
{ {
LOG(INFO) << "user " << mSIPUsername << " state " << mState; LOG(INFO) << "user " << mSIPUsername << " state " << mState;
assert(mBYE); assert(mBYE);
@@ -680,6 +686,17 @@ SIPState SIPEngine::MTDSendOK()
return mState; return mState;
} }
SIPState SIPEngine::MTDSendCANCELOK()
{
LOG(INFO) << "user " << mSIPUsername << " state " << mState;
assert(mCANCEL);
osip_message_t * okay = sip_b_okay(mCANCEL);
gSIPInterface.write(&mProxyAddr,okay);
osip_message_free(okay);
mState = Canceled;
return mState;
}
SIPState SIPEngine::MTCSendTrying() SIPState SIPEngine::MTCSendTrying()
{ {
@@ -772,10 +789,8 @@ SIPState SIPEngine::MTCWaitForACK()
// check for the CANCEL // check for the CANCEL
else if( strcmp(ack->sip_method,"CANCEL") == 0){ else if( strcmp(ack->sip_method,"CANCEL") == 0){
LOG(INFO) << "received CANCEL"; LOG(INFO) << "received CANCEL";
osip_message_t * okay = sip_okay(ack, mSIPUsername.c_str(),mSIPIP.c_str(), mSIPPort); saveCANCEL(ack, false);
gSIPInterface.write(&mProxyAddr,okay); mState=MTDCanceling;
osip_message_free(okay);
mState=Fail;
} }
// check for strays // check for strays
else { else {
@@ -826,10 +841,8 @@ SIPState SIPEngine::MTCCheckForCancel()
// check for the CANCEL // check for the CANCEL
else if (strcmp(msg->sip_method,"CANCEL")==0) { else if (strcmp(msg->sip_method,"CANCEL")==0) {
LOG(INFO) << "received CANCEL"; LOG(INFO) << "received CANCEL";
osip_message_t * okay = sip_okay(msg, mSIPUsername.c_str(),mSIPIP.c_str(), mSIPPort); saveCANCEL(msg, false);
gSIPInterface.write(&mProxyAddr,okay); mState=MTDCanceling;
osip_message_free(okay);
mState=Fail;
} }
// check for strays // check for strays
else { else {

View File

@@ -59,6 +59,8 @@ enum SIPState {
MODClearing, MODClearing,
MODCanceling, MODCanceling,
MTDClearing, MTDClearing,
MTDCanceling,
Canceled,
Cleared, Cleared,
Fail, Fail,
MessageSubmit MessageSubmit
@@ -149,6 +151,10 @@ public:
/** Return the current SIP call state. */ /** Return the current SIP call state. */
SIPState state() const { return mState; } SIPState state() const { return mState; }
/** Return if the call has successfully finished */
bool finished() const { return (mState==Cleared || mState==Canceled); }
/** Set the user to IMSI<IMSI> and generate a call ID; for mobile-originated transactions. */ /** Set the user to IMSI<IMSI> and generate a call ID; for mobile-originated transactions. */
void user( const char * IMSI ); void user( const char * IMSI );
@@ -279,7 +285,9 @@ public:
//@{ //@{
SIPState MTDCheckBYE(); SIPState MTDCheckBYE();
SIPState MTDSendOK(); SIPState MTDSendBYEOK();
SIPState MTDSendCANCELOK();
//@} //@}

View File

@@ -596,12 +596,52 @@ osip_message_t * SIP::sip_bye(const char * req_uri, const char * dialed_number,
osip_message_t * SIP::sip_cancel( osip_message_t * invite) osip_message_t * SIP::sip_cancel( osip_message_t * invite)
{ {
if(invite==NULL){ return NULL;}
osip_message_t * cancel; osip_message_t * cancel;
osip_message_init(&cancel); osip_message_init(&cancel);
osip_message_clone(invite, &cancel); //clone doesn't work -kurtis
//osip_message_clone(invite, &cancel);
// FIXME -- Should use the "force_update" function. // FIXME -- Should use the "force_update" function.
cancel->message_property = 2; cancel->message_property = 2;
//header stuff first
cancel->sip_method = strdup("CANCEL"); cancel->sip_method = strdup("CANCEL");
osip_message_set_version(cancel, strdup("SIP/2.0"));
//uri
osip_uri_init(&cancel->req_uri);
osip_uri_clone(invite->req_uri, &cancel->req_uri);
//via
osip_via_t * via;
char * via_str;
osip_message_get_via(invite, 0, &via);
osip_via_to_str(via, &via_str);
osip_message_set_via(cancel, via_str);
osip_free(via_str);
// from/to header
osip_from_clone(invite->from, &cancel->from);
osip_to_clone(invite->to, &cancel->to);
//contact
osip_contact_t * cont;
char * cont_str;
osip_message_get_contact(invite, 0, &cont);
osip_contact_to_str(cont, &cont_str);
osip_message_set_contact(cancel, cont_str);
osip_free(cont_str);
// Get Call-ID.
osip_call_id_clone(invite->call_id, &cancel->call_id);
// Get Cseq.
osip_cseq_t * cseq;
char * cseq_str;
cseq = osip_message_get_cseq(invite);
osip_cseq_to_str(cseq ,&cseq_str);
osip_message_set_cseq(cancel, cseq_str);
osip_free(cseq_str);
//update message type //update message type
osip_cseq_set_method(cancel->cseq, strdup("CANCEL")); osip_cseq_set_method(cancel->cseq, strdup("CANCEL"));