diff --git a/Control/CallControl.cpp b/Control/CallControl.cpp index bf5e235..891562b 100644 --- a/Control/CallControl.cpp +++ b/Control/CallControl.cpp @@ -136,8 +136,10 @@ void forceSIPClearing(TransactionEntry *transaction) transaction->MODWaitForCANCELOK(); } else { //we received, respond and then don't send ok - //changed state immediately to canceled - transaction->MODSendUnavail(); + //changed state immediately to canceling + transaction->MODSendUNAVAIL(); + //then canceled + transaction->MODWaitForUNAVAILACK(); } } @@ -335,8 +337,8 @@ bool callManagementDispatchGSM(TransactionEntry *transaction, GSM::LogicalChanne transaction->MODWaitFor487(); } else { //if we received it, send a 4** instead - transaction->MODSendUnavail(); - //enventually wait for ACK here -kurtis + transaction->MODSendUNAVAIL(); + transaction->MODWaitForUNAVAILACK(); } transaction->GSMState(GSM::NullState); return true; diff --git a/Control/TransactionTable.cpp b/Control/TransactionTable.cpp index f7dc840..4cff71a 100644 --- a/Control/TransactionTable.cpp +++ b/Control/TransactionTable.cpp @@ -420,10 +420,10 @@ SIP::SIPState TransactionEntry::MODSendBYE() return state; } -SIP::SIPState TransactionEntry::MODSendUnavail() +SIP::SIPState TransactionEntry::MODSendUNAVAIL() { ScopedLock lock(mLock); - SIP::SIPState state = mSIP.MODSendUnavail(); + SIP::SIPState state = mSIP.MODSendUNAVAIL(); echoSIPState(state); return state; } @@ -452,6 +452,14 @@ SIP::SIPState TransactionEntry::MODResendCANCEL() return state; } +SIP::SIPState TransactionEntry::MODResendUNAVAIL() +{ + ScopedLock lock(mLock); + SIP::SIPState state = mSIP.MODResendUNAVAIL(); + echoSIPState(state); + return state; +} + SIP::SIPState TransactionEntry::MODWaitForBYEOK() { ScopedLock lock(mLock); @@ -468,6 +476,14 @@ SIP::SIPState TransactionEntry::MODWaitForCANCELOK() return state; } +SIP::SIPState TransactionEntry::MODWaitForUNAVAILACK() +{ + ScopedLock lock(mLock); + SIP::SIPState state = mSIP.MODWaitForUNAVAILACK(); + echoSIPState(state); + return state; +} + SIP::SIPState TransactionEntry::MODWaitFor487() { ScopedLock lock(mLock); diff --git a/Control/TransactionTable.h b/Control/TransactionTable.h index b666dd8..7cfceed 100644 --- a/Control/TransactionTable.h +++ b/Control/TransactionTable.h @@ -202,12 +202,14 @@ class TransactionEntry { void MTCInitRTP() { ScopedLock lock(mLock); mSIP.MTCInitRTP(); } SIP::SIPState MODSendBYE(); - SIP::SIPState MODSendUnavail(); + SIP::SIPState MODSendUNAVAIL(); SIP::SIPState MODSendCANCEL(); SIP::SIPState MODResendBYE(); SIP::SIPState MODResendCANCEL(); + SIP::SIPState MODResendUNAVAIL(); SIP::SIPState MODWaitForBYEOK(); SIP::SIPState MODWaitForCANCELOK(); + SIP::SIPState MODWaitForUNAVAILACK(); SIP::SIPState MODWaitFor487(); SIP::SIPState MTDCheckBYE(); diff --git a/SIP/SIPEngine.cpp b/SIP/SIPEngine.cpp index 4e606a5..fae102d 100644 --- a/SIP/SIPEngine.cpp +++ b/SIP/SIPEngine.cpp @@ -96,8 +96,8 @@ 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), - mCANCEL(NULL), mSession(NULL), mTxTime(0), mRxTime(0), - mState(NullState), + mCANCEL(NULL), mUNAVAIL(NULL), mSession(NULL), + mTxTime(0), mRxTime(0), mState(NullState), mDTMF('\0'),mDTMFDuration(0) { assert(proxy); @@ -133,6 +133,7 @@ SIPEngine::~SIPEngine() if (mLastResponse!=NULL) osip_message_free(mLastResponse); if (mBYE!=NULL) osip_message_free(mBYE); if (mCANCEL!=NULL) osip_message_free(mCANCEL); + if (mUNAVAIL!=NULL) osip_message_free(mUNAVAIL); // FIXME -- Do we need to dispose of the RtpSesion *mSesison? } @@ -200,6 +201,15 @@ void SIPEngine::saveCANCEL(const osip_message_t *CANCEL, bool mine) osip_message_clone(CANCEL,&mCANCEL); } +void SIPEngine::saveUNAVAIL(const osip_message_t *UNAVAIL, 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 (mUNAVAIL!=NULL) osip_message_free(mUNAVAIL); + osip_message_clone(UNAVAIL,&mUNAVAIL); +} + /* we're going to figure if the from field is us or not */ bool SIPEngine::instigator() { @@ -492,11 +502,13 @@ SIPState SIPEngine::MOCWaitForOK() LOG(DEBUG) << "received status " << status; saveResponse(msg); switch (status) { - case 100: // Trying - case 183: // Progress + case 100: // Trying - this maybe should go to ringing too -kurtis mState = Proceeding; break; case 180: // Ringing + case 183: // Progress - + //We keep sending invited until we + //enter Ringing, so 183 need to do that -kurtis mState = Ringing; break; case 200: // OK @@ -523,16 +535,10 @@ SIPState SIPEngine::MOCWaitForOK() } -//this isn't working right now -kurtis SIPState SIPEngine::MOCSendACK() { assert(mLastResponse); - // new branch - char tmp[50]; - make_branch(tmp); - mViaBranch = tmp; - LOG(INFO) << "user " << mSIPUsername << " state " << mState; osip_message_t* ack = sip_ack( mRemoteDomain.c_str(), @@ -572,7 +578,7 @@ SIPState SIPEngine::MODSendBYE() return mState; } -SIPState SIPEngine::MODSendUnavail() +SIPState SIPEngine::MODSendUNAVAIL() { LOG(INFO) << "user " << mSIPUsername << " state " << mState; assert(mINVITE); @@ -580,8 +586,9 @@ SIPState SIPEngine::MODSendUnavail() osip_message_t * unavail = sip_temporarily_unavailable(mINVITE, mSIPIP.c_str(), mSIPUsername.c_str(), mSIPPort); gSIPInterface.write(&mProxyAddr,unavail); + saveUNAVAIL(unavail, true); osip_message_free(unavail); - mState = Canceled; + mState = MODCanceling; return mState; } @@ -618,6 +625,15 @@ SIPState SIPEngine::MODResendCANCEL() return mState; } +SIPState SIPEngine::MODResendUNAVAIL() +{ + LOG(INFO) << "user " << mSIPUsername << " state " << mState; + assert(mState==MODCanceling); + assert(mUNAVAIL); + gSIPInterface.write(&mProxyAddr,mUNAVAIL); + return mState; +} + /* there shouldn't be any more communications on this fifo, but we might get a 487 RequestTerminated. We only need to respond and move on -kurtis */ SIPState SIPEngine::MODWaitFor487() @@ -710,6 +726,35 @@ SIPState SIPEngine::MODWaitForCANCELOK() return mState; } +SIPState SIPEngine::MODWaitForUNAVAILACK() +{ + LOG(INFO) << "user " << mSIPUsername << " state " << mState; + bool responded = false; + Timeval timeout(gConfig.getNum("SIP.Timer.F")); + while (!timeout.passed()) { + try { + osip_message_t * ack = gSIPInterface.read(mCallID, gConfig.getNum("SIP.Timer.E")); + responded = true; + saveResponse(ack); + if (!strncmp(ack->sip_method,"ACK", 4)) { + LOG(WARNING) << "unexpected " << ack->sip_method << " response to UNAVAIL, from proxy " << mProxyIP << ":" << mProxyPort << ". Assuming other end has cleared"; + } + osip_message_free(ack); + break; + } + catch (SIPTimeout& e) { + LOG(NOTICE) << "response timeout, resending UNAVAIL"; + MODResendUNAVAIL(); + } + } + + if (!responded) { LOG(ALERT) << "lost contact with proxy " << mProxyIP << ":" << mProxyPort; } + + mState = Canceled; + + return mState; +} + SIPState SIPEngine::MTDCheckBYE() { //LOG(DEBUG) << "user " << mSIPUsername << " state " << mState; diff --git a/SIP/SIPEngine.h b/SIP/SIPEngine.h index bca3161..1933294 100644 --- a/SIP/SIPEngine.h +++ b/SIP/SIPEngine.h @@ -110,8 +110,10 @@ private: //@{ osip_message_t * mINVITE; ///< the INVITE message for this transaction osip_message_t * mLastResponse; ///< the last response received for this transaction + //we should maybe push these together sometime? -kurtis osip_message_t * mBYE; ///< the BYE message for this transaction osip_message_t * mCANCEL; ///< the CANCEL message for this transaction + osip_message_t * mUNAVAIL; ///< the UNAVAIL message for this transaction //@} /**@name RTP state and parameters. */ @@ -277,7 +279,7 @@ public: //@{ SIPState MODSendBYE(); - SIPState MODSendUnavail(); + SIPState MODSendUNAVAIL(); SIPState MODSendCANCEL(); @@ -285,10 +287,14 @@ public: SIPState MODResendCANCEL(); + SIPState MODResendUNAVAIL(); + SIPState MODWaitForBYEOK(); SIPState MODWaitForCANCELOK(); + SIPState MODWaitForUNAVAILACK(); + SIPState MODWaitFor487(); //@} @@ -349,6 +355,9 @@ public: /** Save a copy of a CANCEL message in the engine. */ void saveCANCEL(const osip_message_t *CANCEL, bool mine); + /** Save a copy of a UNAVAIL message in the engine. */ + void saveUNAVAIL(const osip_message_t *UNAVAIL, bool mine); + private: