📄 transactionstate.cxx
字号:
#if defined(HAVE_CONFIG_H)#include "resip/stack/config.hxx"#endif#include "resip/stack/ConnectionTerminated.hxx"#include "resip/stack/DnsInterface.hxx"#include "resip/stack/DnsResult.hxx"#include "resip/stack/Helper.hxx"#include "resip/stack/MethodTypes.hxx"#include "resip/stack/SipMessage.hxx"#include "resip/stack/SipStack.hxx"#include "resip/stack/StatisticsManager.hxx"#include "resip/stack/TimerMessage.hxx"#include "resip/stack/TransactionController.hxx"#include "resip/stack/TransactionMessage.hxx"#include "resip/stack/TransactionState.hxx"#include "resip/stack/TransactionTerminated.hxx"#include "resip/stack/TransportFailure.hxx"#include "resip/stack/TransactionUserMessage.hxx"#include "resip/stack/TransportFailure.hxx"#include "resip/stack/TransportSelector.hxx"#include "resip/stack/TransactionUser.hxx"#include "resip/stack/TuSelector.hxx"#include "rutil/DnsUtil.hxx"#include "rutil/Logger.hxx"#include "rutil/MD5Stream.hxx"#include "rutil/Socket.hxx"#include "rutil/Random.hxx"#include "rutil/WinLeakCheck.hxx"#include "resip/stack/KeepAliveMessage.hxx"using namespace resip;#define RESIPROCATE_SUBSYSTEM Subsystem::TRANSACTIONunsigned long TransactionState::StatelessIdCounter = 0;TransactionState::TransactionState(TransactionController& controller, Machine m, State s, const Data& id, TransactionUser* tu) : mController(controller), mMachine(m), mState(s), mIsCancel(false), mIsReliable(true), // !jf! mMsgToRetransmit(0), mDnsResult(0), mId(id), mAckIsValid(false), mWaitingForDnsResult(false), mTransactionUser(tu), mFailureReason(TransportFailure::None){ StackLog (<< "Creating new TransactionState: " << *this);}TransactionState* TransactionState::makeCancelTransaction(TransactionState* tr, Machine machine, const Data& tid){ TransactionState* cancel = new TransactionState(tr->mController, machine, Trying, tid, tr->mTransactionUser); // !jf! don't set this since it will be set by TransactionState::processReliability() //cancel->mIsReliable = tr->mIsReliable; cancel->mResponseTarget = tr->mResponseTarget; cancel->mIsCancel = true; cancel->mTarget = tr->mTarget; cancel->add(tid); // !jf! don't call processServerNonInvite since it will delete // the sip message which needs to get sent to the TU cancel->processReliability(tr->mTarget.getType()); return cancel;}boolTransactionState::handleBadRequest(const resip::SipMessage& badReq, TransactionController& controller){ assert(badReq.isRequest() && badReq.method() != ACK); try { SipMessage* error = Helper::makeResponse(badReq,400); error->header(h_StatusLine).reason()+="(" + badReq.getReason() + ")"; Tuple target(badReq.getSource()); if(badReq.isExternal()) { controller.mTransportSelector.transmit(error,target); delete error; return true; } else { // ?bwc? Should we put together a TransactionState here so we can // send a 400 to the TU? // TODO if we send the error to the TU, don't delete the error delete error; return false; } } catch(resip::BaseException& e) { ErrLog(<< "Exception thrown in TransactionState::handleBadRequest." " This shouldn't happen. " << e); return false; }}TransactionState::~TransactionState(){ assert(mState != Bogus); if (mDnsResult) { mDnsResult->destroy(); } //StackLog (<< "Deleting TransactionState " << mId << " : " << this); erase(mId); delete mMsgToRetransmit; mMsgToRetransmit = 0; mState = Bogus;}voidTransactionState::process(TransactionController& controller){ TransactionMessage* message = controller.mStateMacFifo.getNext(); { KeepAliveMessage* keepAlive = dynamic_cast<KeepAliveMessage*>(message); if (keepAlive) { StackLog ( << "Sending keep alive to: " << keepAlive->getDestination()); controller.mTransportSelector.transmit(keepAlive, keepAlive->getDestination()); delete keepAlive; return; } ConnectionTerminated* term = dynamic_cast<ConnectionTerminated*>(message); if (term) { controller.mTuSelector.add(term); delete term; return; } } // .bwc. We can't do anything without a tid here. Check this first. Data tid; try { tid = message->getTransactionId(); } catch(SipMessage::Exception&) { // .bwc This is not our error. Do not ErrLog. DebugLog( << "TransactionState::process dropping message with invalid tid " << message->brief()); delete message; return; } SipMessage* sip = dynamic_cast<SipMessage*>(message); if(sip) { // ?bwc? Should this come after checking for error conditions? if(controller.mStack.statisticsManagerEnabled() && sip->isExternal()) { controller.mStatsManager.received(sip); } // .bwc. Check for error conditions we can respond to. if(sip->isRequest() && sip->method() != ACK) { if(sip->isExternal() && controller.isTUOverloaded()) { SipMessage* tryLater = Helper::makeResponse(*sip, 503); tryLater->header(h_RetryAfter).value() = 32 + (Random::getRandom() % 32); tryLater->header(h_RetryAfter).comment() = "Server busy TRANS"; Tuple target(sip->getSource()); delete sip; controller.mTransportSelector.transmit(tryLater, target); delete tryLater; return; } if(sip->isInvalid()) { handleBadRequest(*sip,controller); delete sip; return; } }#ifdef PEDANTIC_STACK try { sip->parseAllHeaders(); } catch(resip::ParseException& e) { if(sip->isRequest() && sip->method()!=ACK) { handleBadRequest(*sip,controller); } InfoLog(<< "Exception caught by pedantic stack: " << e); }#endif // This ensures that CANCEL requests form unique transactions if (sip->method() == CANCEL) { tid += "cancel"; } } TransactionState* state = 0; if (message->isClientTransaction()) state = controller.mClientTransactionMap.find(tid); else state = controller.mServerTransactionMap.find(tid); if (state && sip && sip->isExternal()) { // .bwc. This code (if enabled) ensures that responses have the same // CallId and tags as the request did (excepting the introduction of a // remote tag). This is to protect dialog-stateful TUs that don't react // gracefully when a stupid/malicious endpoint fiddles with the tags // and/or CallId when it isn't supposed to. (DUM is one such TU) if(state->mController.getFixBadDialogIdentifiers() && sip->isResponse() && state->mMsgToRetransmit) { if(sip->header(h_CallId).isWellFormed()) { if(!(sip->header(h_CallId) == state->mMsgToRetransmit->header(h_CallId))) { InfoLog(<< "Other end modified our Call-Id... correcting."); sip->header(h_CallId) = state->mMsgToRetransmit->header(h_CallId); } } else { InfoLog(<< "Other end corrupted our CallId... correcting."); sip->header(h_CallId) = state->mMsgToRetransmit->header(h_CallId); } NameAddr& from = state->mMsgToRetransmit->header(h_From); if(sip->header(h_From).isWellFormed()) { // Overwrite tag. if(from.exists(p_tag)) { if(sip->header(h_From).param(p_tag) != from.param(p_tag)) { InfoLog(<<"Other end modified our local tag... correcting."); sip->header(h_From).param(p_tag) = from.param(p_tag); } } else if(sip->header(h_From).exists(p_tag)) { if(sip->header(h_From).exists(p_tag)) { InfoLog(<<"Other end added a local tag for us... removing."); sip->header(h_From).remove(p_tag); } } } else { InfoLog(<<"Other end corrupted our From header... replacing."); // Whole header is hosed, overwrite. sip->header(h_From) = from; } NameAddr& to = state->mMsgToRetransmit->header(h_To); if(sip->header(h_To).isWellFormed()) { // Overwrite tag. if(to.exists(p_tag)) { if(sip->header(h_To).param(p_tag) != to.param(p_tag)) { InfoLog(<<"Other end modified the (existing) remote tag... " "correcting."); sip->header(h_To).param(p_tag) = to.param(p_tag); } } } else { InfoLog(<<"Other end corrupted our To header... replacing."); // Whole header is hosed, overwrite. sip->header(h_To) = to; } } // .bwc. This code ensures that the transaction state-machine can recover // from ACK/200 with the same tid as the original INVITE. This problem is // stupidly common. if(sip->isRequest() && sip->method() == ACK && !state->mAckIsValid) { // Must have received an ACK to a 200; // We will never respond to this, so nothing will need this tid for // driving transaction state. Additionally, InfoLog(<<"Someone sent us an ACK/200 with the same tid as the " "original INVITE. This is bad behavior, and should be " "corrected in the client."); sip->mIsBadAck200=true; // .bwc. This is a new stateless transaction, despite its tid. state=0; } } if (state) // found transaction for sip msg { StackLog (<< "Found matching transaction for " << message->brief() << " -> " << *state); switch (state->mMachine) { case ClientNonInvite: state->processClientNonInvite(message); break; case ClientInvite: // ACK from TU will be Stateless assert (!(state->isFromTU(sip) && sip->isRequest() && sip->method() == ACK)); state->processClientInvite(message); break; case ServerNonInvite: state->processServerNonInvite(message); break; case ServerInvite: state->processServerInvite(message); break; case Stateless: state->processStateless(message); break; case ClientStale: state->processClientStale(message); break; case ServerStale: state->processServerStale(message); break; default: CritLog(<<"internal state error"); assert(0); return; } } else if (sip) // new transaction { StackLog (<< "No matching transaction for " << sip->brief()); TransactionUser* tu = 0; if (sip->isExternal()) { if (controller.mTuSelector.haveTransactionUsers() && sip->isRequest()) { tu = controller.mTuSelector.selectTransactionUser(*sip); if (!tu) { //InfoLog (<< "Didn't find a TU for " << sip->brief()); // !bwc! We really should do something other than a 500 here. // If none of the TUs liked the request because of the Request- // Uri scheme, we should be returning a 416, for example. InfoLog( << "No TU found for message: " << sip->brief()); SipMessage* noMatch = Helper::makeResponse(*sip, 500); Tuple target(sip->getSource()); delete sip; controller.mTransportSelector.transmit(noMatch, target); delete noMatch; return; } else { //InfoLog (<< "Found TU for " << sip->brief()); } } } else { tu = sip->getTransactionUser(); if (!tu) { //InfoLog (<< "No TU associated with " << sip->brief()); } } if (sip->isRequest()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -