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
This commit is contained in:
Kurtis Heimerl
2012-01-09 01:01:12 +00:00
parent fcbedbb000
commit f98838c76a
7 changed files with 107 additions and 10 deletions

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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();
}
}
}

View File

@@ -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:

View File

@@ -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)
{

View File

@@ -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 );