From f98838c76ab7c788dbaaba582527e201fcc438cf Mon Sep 17 00:00:00 2001 From: Kurtis Heimerl Date: Mon, 9 Jan 2012 01:01:12 +0000 Subject: [PATCH] Fixed Bug #172, OpenBTS now sends CANCEL messages when there is no active call (instead of BYE) git-svn-id: http://wush.net/svn/range/software/public/openbts/trunk@3006 19bc5d8c-e614-43d4-8b26-e1612bc8e597 --- Control/CallControl.cpp | 23 +++++++++++++---- Control/TransactionTable.cpp | 16 ++++++++++++ Control/TransactionTable.h | 2 ++ SIP/SIPEngine.cpp | 50 ++++++++++++++++++++++++++++++++---- SIP/SIPEngine.h | 9 +++++++ SIP/SIPMessage.cpp | 16 ++++++++++++ SIP/SIPMessage.h | 1 + 7 files changed, 107 insertions(+), 10 deletions(-) diff --git a/Control/CallControl.cpp b/Control/CallControl.cpp index d71f09b..1bf928e 100644 --- a/Control/CallControl.cpp +++ b/Control/CallControl.cpp @@ -119,11 +119,16 @@ void forceSIPClearing(TransactionEntry *transaction) SIP::SIPState state = transaction->SIPState(); LOG(INFO) << "SIP state " << state; if (state==SIP::Cleared) return; - if (state!=SIP::MODClearing) { - // This also changes the SIP state to "clearing". + if (state==SIP::Active){ + //Changes state to clearing transaction->MODSendBYE(); - } else { + } else if (state==SIP::MODCanceling){ + transaction->MODResendCANCEL(); + } else if (state==SIP::MODClearing) { transaction->MODResendBYE(); + } else { + //Changes state to canceling + transaction->MODSendCANCEL(); } transaction->MODWaitForOK(); } @@ -300,8 +305,16 @@ bool callManagementDispatchGSM(TransactionEntry *transaction, GSM::LogicalChanne LCH->send(GSM::L3Release(transaction->L3TI())); transaction->setTimer("308"); transaction->GSMState(GSM::ReleaseRequest); - // FIXME -- Maybe we need to send CANCEL. See ticket #172. - transaction->MODSendBYE(); + //bug #172 fixed + if (transaction->SIPState()==SIP::Active){ + transaction->MODSendBYE(); + } + else{ + transaction->MODSendCANCEL(); + //if we disconnect, we don't get another + //of these, wait here? -kurtis + transaction->MODWaitForOK(); + } return false; } diff --git a/Control/TransactionTable.cpp b/Control/TransactionTable.cpp index 9ac189d..75643b7 100644 --- a/Control/TransactionTable.cpp +++ b/Control/TransactionTable.cpp @@ -420,6 +420,14 @@ SIP::SIPState TransactionEntry::MODSendBYE() return state; } +SIP::SIPState TransactionEntry::MODSendCANCEL() +{ + ScopedLock lock(mLock); + SIP::SIPState state = mSIP.MODSendCANCEL(); + echoSIPState(state); + return state; +} + SIP::SIPState TransactionEntry::MODResendBYE() { ScopedLock lock(mLock); @@ -428,6 +436,14 @@ SIP::SIPState TransactionEntry::MODResendBYE() return state; } +SIP::SIPState TransactionEntry::MODResendCANCEL() +{ + ScopedLock lock(mLock); + SIP::SIPState state = mSIP.MODResendCANCEL(); + echoSIPState(state); + return state; +} + SIP::SIPState TransactionEntry::MODWaitForOK() { ScopedLock lock(mLock); diff --git a/Control/TransactionTable.h b/Control/TransactionTable.h index 222d91a..51fae87 100644 --- a/Control/TransactionTable.h +++ b/Control/TransactionTable.h @@ -198,7 +198,9 @@ class TransactionEntry { void MTCInitRTP() { ScopedLock lock(mLock); mSIP.MTCInitRTP(); } SIP::SIPState MODSendBYE(); + SIP::SIPState MODSendCANCEL(); SIP::SIPState MODResendBYE(); + SIP::SIPState MODResendCANCEL(); SIP::SIPState MODWaitForOK(); SIP::SIPState MTDCheckBYE(); diff --git a/SIP/SIPEngine.cpp b/SIP/SIPEngine.cpp index 8f9d134..a6aee25 100644 --- a/SIP/SIPEngine.cpp +++ b/SIP/SIPEngine.cpp @@ -69,6 +69,7 @@ const char* SIP::SIPStateString(SIPState s) case Fail: return "Fail"; case Busy: return "Busy"; case MODClearing: return "MODClearing"; + case MODCanceling: return "MODCanceling"; case MTDClearing: return "MTDClearing"; case Cleared: return "Cleared"; case MessageSubmit: return "SMS-Submit"; @@ -93,7 +94,7 @@ SIPEngine::SIPEngine(const char* proxy, const char* IMSI) mSIPPort(gConfig.getNum("SIP.Local.Port")), mSIPIP(gConfig.getStr("SIP.Local.IP")), mINVITE(NULL), mLastResponse(NULL), mBYE(NULL), - mSession(NULL),mTxTime(0), mRxTime(0), + mCANCEL(NULL), mSession(NULL), mTxTime(0), mRxTime(0), mState(NullState), mDTMF('\0'),mDTMFDuration(0) { @@ -126,6 +127,7 @@ SIPEngine::~SIPEngine() if (mINVITE!=NULL) osip_message_free(mINVITE); if (mLastResponse!=NULL) osip_message_free(mLastResponse); if (mBYE!=NULL) osip_message_free(mBYE); + if (mCANCEL!=NULL) osip_message_free(mCANCEL); // FIXME -- Do we need to dispose of the RtpSesion *mSesison? } @@ -184,6 +186,15 @@ void SIPEngine::saveBYE(const osip_message_t *BYE, bool mine) osip_message_clone(BYE,&mBYE); } +void SIPEngine::saveCANCEL(const osip_message_t *CANCEL, bool mine) +{ + // Instead of cloning, why not just keep the old one? + // Because that doesn't work in all calling contexts. + // This simplifies the call-handling logic. + if (mCANCEL!=NULL) osip_message_free(mCANCEL); + osip_message_clone(CANCEL,&mCANCEL); +} + void SIPEngine::user( const char * IMSI ) @@ -548,6 +559,20 @@ SIPState SIPEngine::MODSendBYE() return mState; } +SIPState SIPEngine::MODSendCANCEL() +{ + LOG(INFO) << "user " << mSIPUsername << " state " << mState; + assert(mINVITE); + + osip_message_t * cancel = sip_cancel(mINVITE); + gSIPInterface.write(&mProxyAddr,cancel); + saveCANCEL(cancel, true); + osip_message_free(cancel); + mState = MODCanceling; + return mState; +} + + SIPState SIPEngine::MODResendBYE() { LOG(INFO) << "user " << mSIPUsername << " state " << mState; @@ -557,12 +582,21 @@ SIPState SIPEngine::MODResendBYE() return mState; } +SIPState SIPEngine::MODResendCANCEL() +{ + LOG(INFO) << "user " << mSIPUsername << " state " << mState; + assert(mState==MODCanceling); + assert(mCANCEL); + gSIPInterface.write(&mProxyAddr,mCANCEL); + return mState; +} + SIPState SIPEngine::MODWaitForOK() { LOG(INFO) << "user " << mSIPUsername << " state " << mState; bool responded = false; - Timeval byeTimeout(gConfig.getNum("SIP.Timer.F")); - while (!byeTimeout.passed()) { + Timeval timeout(gConfig.getNum("SIP.Timer.F")); + while (!timeout.passed()) { try { osip_message_t * ok = gSIPInterface.read(mCallID, gConfig.getNum("SIP.Timer.E")); responded = true; @@ -575,8 +609,14 @@ SIPState SIPEngine::MODWaitForOK() break; } catch (SIPTimeout& e) { - LOG(NOTICE) << "response timeout, resending BYE"; - MODResendBYE(); + //this is sketchy -kurtis + if (mState==MODCanceling){ + LOG(NOTICE) << "response timeout, resending CANCEL"; + MODResendCANCEL(); + } else { + LOG(NOTICE) << "response timeout, resending BYE"; + MODResendBYE(); + } } } diff --git a/SIP/SIPEngine.h b/SIP/SIPEngine.h index a3604b4..cfa5429 100644 --- a/SIP/SIPEngine.h +++ b/SIP/SIPEngine.h @@ -57,6 +57,7 @@ enum SIPState { Connecting, Active, MODClearing, + MODCanceling, MTDClearing, Cleared, Fail, @@ -108,6 +109,7 @@ private: osip_message_t * mINVITE; ///< the INVITE message for this transaction osip_message_t * mLastResponse; ///< the last response received for this transaction osip_message_t * mBYE; ///< the BYE message for this transaction + osip_message_t * mCANCEL; ///< the CANCEL message for this transaction //@} /**@name RTP state and parameters. */ @@ -263,8 +265,12 @@ public: //@{ SIPState MODSendBYE(); + SIPState MODSendCANCEL(); + SIPState MODResendBYE(); + SIPState MODResendCANCEL(); + SIPState MODWaitForOK(); //@} @@ -320,6 +326,9 @@ public: /** Save a copy of a BYE message in the engine. */ void saveBYE(const osip_message_t *BYE, bool mine); + /** Save a copy of a CANCEL message in the engine. */ + void saveCANCEL(const osip_message_t *CANCEL, bool mine); + private: diff --git a/SIP/SIPMessage.cpp b/SIP/SIPMessage.cpp index 1f74ce3..de0dddb 100644 --- a/SIP/SIPMessage.cpp +++ b/SIP/SIPMessage.cpp @@ -592,6 +592,22 @@ osip_message_t * SIP::sip_bye(const char * req_uri, const char * dialed_number, return bye; } +/* Cancel a previous invite */ +osip_message_t * SIP::sip_cancel( osip_message_t * invite) +{ + + osip_message_t * cancel; + osip_message_init(&cancel); + osip_message_clone(invite, &cancel); + // FIXME -- Should use the "force_update" function. + cancel->message_property = 2; + cancel->sip_method = strdup("CANCEL"); + + //update message type + osip_cseq_set_method(cancel->cseq, strdup("CANCEL")); + + return cancel; +} osip_message_t * SIP::sip_okay_sdp( osip_message_t * inv, const char * sip_username, const char * local_ip, short wlocal_port, short rtp_port, unsigned audio_codec) { diff --git a/SIP/SIPMessage.h b/SIP/SIPMessage.h index a706ccd..26ed25a 100644 --- a/SIP/SIPMessage.h +++ b/SIP/SIPMessage.h @@ -49,6 +49,7 @@ osip_message_t * sip_ack( const char * req_uri, const char * dialed_number, cons osip_message_t * sip_bye( const char * req_uri, const char * dialed_number, const char * sip_username, short local_port, const char * local_ip, const char * proxy_ip, short proxy_port, const osip_from_t *from_header, const osip_to_t * to_header, const char * via_branch, const osip_call_id_t* call_id_header, int cseq); +osip_message_t * sip_cancel( osip_message_t * invite); osip_message_t * sip_okay_sdp( osip_message_t * inv, const char * sip_username, const char * local_ip, short wlocal_port, short rtp_port, unsigned audio_codecs );