diff --git a/Control/CallControl.cpp b/Control/CallControl.cpp index 891562b..9a653f9 100644 --- a/Control/CallControl.cpp +++ b/Control/CallControl.cpp @@ -137,9 +137,9 @@ void forceSIPClearing(TransactionEntry *transaction) } else { //we received, respond and then don't send ok //changed state immediately to canceling - transaction->MODSendUNAVAIL(); + transaction->MODSendERROR(NULL, 480, "Temporarily Unavailable", true); //then canceled - transaction->MODWaitForUNAVAILACK(); + transaction->MODWaitForERRORACK(true); } } @@ -337,8 +337,8 @@ bool callManagementDispatchGSM(TransactionEntry *transaction, GSM::LogicalChanne transaction->MODWaitFor487(); } else { //if we received it, send a 4** instead - transaction->MODSendUNAVAIL(); - transaction->MODWaitForUNAVAILACK(); + transaction->MODSendERROR(NULL, 480, "Temporarily Unavailable", true); + transaction->MODWaitForERRORACK(true); } transaction->GSMState(GSM::NullState); return true; @@ -866,7 +866,7 @@ void Control::MOCController(TransactionEntry *transaction, GSM::TCHFACCHLogicalC TCH->send(GSM::L3Progress(L3TI)); break; case SIP::Timeout: - LOG(NOTICE) << "SIP:Timeout, reinvite"; + LOG(ALERT) << "MOC INVITE Timed out. Is SIP.Proxy.Speech (" << gConfig.getStr("SIP.Proxy.Speech") << ") configured correctly?"; state = transaction->MOCResendINVITE(); break; default: diff --git a/Control/TransactionTable.cpp b/Control/TransactionTable.cpp index 4cff71a..3dbf66b 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::MODSendERROR(osip_message_t * cause, int code, const char * reason, bool cancel) { ScopedLock lock(mLock); - SIP::SIPState state = mSIP.MODSendUNAVAIL(); + SIP::SIPState state = mSIP.MODSendERROR(cause, code, reason, cancel); echoSIPState(state); return state; } @@ -452,10 +452,10 @@ SIP::SIPState TransactionEntry::MODResendCANCEL() return state; } -SIP::SIPState TransactionEntry::MODResendUNAVAIL() +SIP::SIPState TransactionEntry::MODResendERROR(bool cancel) { ScopedLock lock(mLock); - SIP::SIPState state = mSIP.MODResendUNAVAIL(); + SIP::SIPState state = mSIP.MODResendERROR(cancel); echoSIPState(state); return state; } @@ -476,10 +476,10 @@ SIP::SIPState TransactionEntry::MODWaitForCANCELOK() return state; } -SIP::SIPState TransactionEntry::MODWaitForUNAVAILACK() +SIP::SIPState TransactionEntry::MODWaitForERRORACK(bool cancel) { ScopedLock lock(mLock); - SIP::SIPState state = mSIP.MODWaitForUNAVAILACK(); + SIP::SIPState state = mSIP.MODWaitForERRORACK(cancel); echoSIPState(state); return state; } diff --git a/Control/TransactionTable.h b/Control/TransactionTable.h index 7cfceed..5a4568f 100644 --- a/Control/TransactionTable.h +++ b/Control/TransactionTable.h @@ -202,14 +202,14 @@ class TransactionEntry { void MTCInitRTP() { ScopedLock lock(mLock); mSIP.MTCInitRTP(); } SIP::SIPState MODSendBYE(); - SIP::SIPState MODSendUNAVAIL(); + SIP::SIPState MODSendERROR(osip_message_t * cause, int code, const char * reason, bool cancel); SIP::SIPState MODSendCANCEL(); SIP::SIPState MODResendBYE(); SIP::SIPState MODResendCANCEL(); - SIP::SIPState MODResendUNAVAIL(); + SIP::SIPState MODResendERROR(bool cancel); SIP::SIPState MODWaitForBYEOK(); SIP::SIPState MODWaitForCANCELOK(); - SIP::SIPState MODWaitForUNAVAILACK(); + SIP::SIPState MODWaitForERRORACK(bool cancel); SIP::SIPState MODWaitFor487(); SIP::SIPState MTDCheckBYE(); @@ -241,6 +241,9 @@ class TransactionEntry { void saveBYE(const osip_message_t* bye, bool local) { ScopedLock lock(mLock); mSIP.saveBYE(bye,local); } + bool sameINVITE(osip_message_t * msg) + { ScopedLock lock(mLock); return mSIP.sameINVITE(msg); } + //@} unsigned stateAge() const { ScopedLock lock(mLock); return mStateTimer.elapsed(); } diff --git a/SIP/SIPEngine.cpp b/SIP/SIPEngine.cpp index 42751aa..215c295 100644 --- a/SIP/SIPEngine.cpp +++ b/SIP/SIPEngine.cpp @@ -96,7 +96,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), - mCANCEL(NULL), mUNAVAIL(NULL), mSession(NULL), + mCANCEL(NULL), mERROR(NULL), mSession(NULL), mTxTime(0), mRxTime(0), mState(NullState), mDTMF('\0'),mDTMFDuration(0) { @@ -133,7 +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); + if (mERROR!=NULL) osip_message_free(mERROR); // FIXME -- Do we need to dispose of the RtpSesion *mSesison? } @@ -201,13 +201,13 @@ 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) +void SIPEngine::saveERROR(const osip_message_t *ERROR, 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); + if (mERROR!=NULL) osip_message_free(mERROR); + osip_message_clone(ERROR,&mERROR); } /* we're going to figure if the from field is us or not */ @@ -578,17 +578,24 @@ SIPState SIPEngine::MODSendBYE() return mState; } -SIPState SIPEngine::MODSendUNAVAIL() +SIPState SIPEngine::MODSendERROR(osip_message_t * cause, int code, const char * reason, bool cancel) { LOG(INFO) << "user " << mSIPUsername << " state " << mState; - assert(mINVITE); - - osip_message_t * unavail = sip_temporarily_unavailable(mINVITE, mSIPIP.c_str(), - mSIPUsername.c_str(), mSIPPort); + if (NULL == cause){ + assert(mINVITE); + cause = mINVITE; + } + + /* 480 is unavail */ + osip_message_t * unavail = sip_error(cause, mSIPIP.c_str(), + mSIPUsername.c_str(), mSIPPort, + code, reason); gSIPInterface.write(&mProxyAddr,unavail); - saveUNAVAIL(unavail, true); + saveERROR(unavail, true); osip_message_free(unavail); - mState = MODCanceling; + if (cancel){ + mState = MODCanceling; + } return mState; } @@ -625,12 +632,14 @@ SIPState SIPEngine::MODResendCANCEL() return mState; } -SIPState SIPEngine::MODResendUNAVAIL() +SIPState SIPEngine::MODResendERROR(bool cancel) { LOG(INFO) << "user " << mSIPUsername << " state " << mState; - assert(mState==MODCanceling); - assert(mUNAVAIL); - gSIPInterface.write(&mProxyAddr,mUNAVAIL); + if (cancel){ + if (mState!=MODCanceling) LOG(ERR) << "incorrect state for this method"; + } + assert(mERROR); + gSIPInterface.write(&mProxyAddr,mERROR); return mState; } @@ -726,7 +735,7 @@ SIPState SIPEngine::MODWaitForCANCELOK() return mState; } -SIPState SIPEngine::MODWaitForUNAVAILACK() +SIPState SIPEngine::MODWaitForERRORACK(bool cancel) { LOG(INFO) << "user " << mSIPUsername << " state " << mState; bool responded = false; @@ -737,20 +746,22 @@ SIPState SIPEngine::MODWaitForUNAVAILACK() responded = true; saveResponse(ack); if ((NULL == ack->sip_method) || !strncmp(ack->sip_method,"ACK", 4)) { - LOG(WARNING) << "unexpected response to UNAVAIL, from proxy " << mProxyIP << ":" << mProxyPort << ". Assuming other end has cleared"; + LOG(WARNING) << "unexpected response to ERROR, from proxy " << mProxyIP << ":" << mProxyPort << ". Assuming other end has cleared"; } osip_message_free(ack); break; } catch (SIPTimeout& e) { - LOG(NOTICE) << "response timeout, resending UNAVAIL"; - MODResendUNAVAIL(); + LOG(NOTICE) << "response timeout, resending ERROR"; + MODResendERROR(cancel); } } if (!responded) { LOG(ALERT) << "lost contact with proxy " << mProxyIP << ":" << mProxyPort; } - mState = Canceled; + if (cancel){ + mState = Canceled; + } return mState; } @@ -1212,7 +1223,31 @@ bool SIPEngine::sendINFOAndWaitForOK(unsigned wInfo) }; - - +/* reinvite stuff */ +/* return true if this is the same invite as the one we have stored */ +bool SIPEngine::sameINVITE(osip_message_t * msg){ + assert(mINVITE); + if (NULL == msg){ + return false; + } + char* old_inv; + size_t old_len; + char* new_inv; + size_t new_len; + int res = 0; //does not match + //this sometimes fails even though mINVITE is real. No idea -k + osip_message_to_str(mINVITE, &old_inv, &old_len); + osip_message_to_str(msg, &new_inv, &new_len); + if (old_inv && new_inv){ + res = !(strncmp(old_inv, new_inv, old_len)); + } + if (old_inv){ + free(old_inv); + } + if (new_inv){ + free(new_inv); + } + return res; +} // vim: ts=4 sw=4 diff --git a/SIP/SIPEngine.h b/SIP/SIPEngine.h index 1933294..71c03ca 100644 --- a/SIP/SIPEngine.h +++ b/SIP/SIPEngine.h @@ -113,7 +113,7 @@ private: //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 + osip_message_t * mERROR; ///< the ERROR message for this transaction //@} /**@name RTP state and parameters. */ @@ -279,7 +279,7 @@ public: //@{ SIPState MODSendBYE(); - SIPState MODSendUNAVAIL(); + SIPState MODSendERROR(osip_message_t * cause, int code, const char * reason, bool cancel); SIPState MODSendCANCEL(); @@ -287,13 +287,13 @@ public: SIPState MODResendCANCEL(); - SIPState MODResendUNAVAIL(); + SIPState MODResendERROR(bool cancel); SIPState MODWaitForBYEOK(); SIPState MODWaitForCANCELOK(); - SIPState MODWaitForUNAVAILACK(); + SIPState MODWaitForERRORACK(bool cancel); SIPState MODWaitFor487(); //@} @@ -355,10 +355,12 @@ 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); - + /** Save a copy of a ERROR message in the engine. */ + void saveERROR(const osip_message_t *ERROR, bool mine); + + /** Determine if this invite matches the saved one */ + bool sameINVITE(osip_message_t * msg); private: diff --git a/SIP/SIPInterface.cpp b/SIP/SIPInterface.cpp index 1f21edc..ba83e86 100644 --- a/SIP/SIPInterface.cpp +++ b/SIP/SIPInterface.cpp @@ -379,6 +379,15 @@ bool SIPInterface::checkInvite( osip_message_t * msg) mSIPMap.remove(callIDNum); return false; } + //if this is not the saved invite, it's a RE-invite. Respond saying we don't support it. + if (!transaction->sameINVITE(msg)){ + /* don't cancel the call */ + transaction->MODSendERROR(msg, 488, "Not Acceptable Here", false); + /* I think we'd need to create a new transaction for this ack. Right now, just assume the ack makes it back. + if not, we'll hear another INVITE */ + //transaction->MODWaitForERRORACK(false); //don't cancel the call + return false; + } // There is transaction already. Send trying. transaction->MTCSendTrying(); // And if no channel is established yet, page again. diff --git a/SIP/SIPMessage.cpp b/SIP/SIPMessage.cpp index c700144..c475f4d 100644 --- a/SIP/SIPMessage.cpp +++ b/SIP/SIPMessage.cpp @@ -599,7 +599,7 @@ osip_message_t * SIP::sip_bye(const char * req_uri, const char * dialed_number, return bye; } -osip_message_t * SIP::sip_temporarily_unavailable( osip_message_t * invite, const char * host, const char * username, short port) +osip_message_t * SIP::sip_error(osip_message_t * invite, const char * host, const char * username, short port, short code, const char* reason) { if(invite==NULL){ return NULL;} @@ -610,8 +610,8 @@ osip_message_t * SIP::sip_temporarily_unavailable( osip_message_t * invite, con // FIXME -- Should use the "force_update" function. unavail->message_property = 2; //header stuff first - unavail->status_code = 480; - unavail->reason_phrase = strdup("Temporarily Unavailable"); + unavail->status_code = code; + unavail->reason_phrase = strdup(reason); osip_message_set_version(unavail, strdup("SIP/2.0")); char local_port[10]; diff --git a/SIP/SIPMessage.h b/SIP/SIPMessage.h index 81a9aa7..0f60751 100644 --- a/SIP/SIPMessage.h +++ b/SIP/SIPMessage.h @@ -55,7 +55,7 @@ osip_message_t * sip_okay_sdp( osip_message_t * inv, const char * sip_username, osip_message_t * sip_okay( osip_message_t * inv, const char * sip_username, const char * local_ip, short wlocal_port); -osip_message_t * sip_temporarily_unavailable( osip_message_t * invite, const char * host, const char * username, short port); +osip_message_t * sip_error( osip_message_t * invite, const char * host, const char * username, short port, short code, const char* reason); osip_message_t * sip_info(unsigned info, const char *dialed_number, short rtp_port,const char * sip_username, short local_port, const char * local_ip, const char * proxy_ip, const char * from_tag, const char * via_branch, const osip_call_id_t* call_id_header, int cseq); @@ -69,4 +69,3 @@ osip_message_t * sip_ringing( osip_message_t * invite, const char * sip_username }; #endif -