📄 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::TRANSACTION
unsigned 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),
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;
}
bool
TransactionState::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()+="(" + error->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;
}
void
TransactionState::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&)
{
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::ParseBuffer::Exception& 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);
// this code makes sure that an ACK to a 200 is going to create a new
// stateless transaction. In an ACK to a failure response, the mToTag will
// have been set in the ServerTransaction as the 4xx passes through so it
// will match.
if (state && sip && sip->isRequest() && sip->method() == ACK)
{
try
{
if (sip->header(h_To).exists(p_tag) && sip->header(h_To).param(p_tag) != state->mToTag)
{
// Must have received an ACK to a 200;
// !bwc! Please note; this is an incorrect ACK/200. ACK/200 is
// supposed to have a new new tid, although many clients get
// this wrong. It is also possible that a client has set the To tag
// incorrectly in an ACK/failure, but this is much less likely.
// I am conflicted as to whether this code should remain; parsing
// To takes effort, and doing this in order to clean up after
// broken UACs irritates me...
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.");
tid += "ack";
if (message->isClientTransaction()) state = controller.mClientTransactionMap.find(tid);
else state = controller.mServerTransactionMap.find(tid);
// will be sent statelessly, if from TU
}
}
catch(resip::ParseBuffer::Exception& e)
{
// !bwc! Since we were trying to clean up after broken UACs above, we
// just ignore the error and pretend we never looked at To (since we
// technically shouldn't be in the first place).
InfoLog(<<"Someone sent us an ACK inside the INVITE transaction"
" with a malformed To header. Assuming ACK/failure. " << e);
}
}
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())
{
// create a new state object and insert in the TransactionMap
if (sip->isExternal()) // new sip msg from transport
{
if (sip->method() == INVITE)
{
// !rk! This might be needlessly created. Design issue.
TransactionState* state = new TransactionState(controller, ServerInvite, Trying, tid, tu);
state->mMsgToRetransmit = state->make100(sip);
state->mResponseTarget = sip->getSource(); // UACs source address
// !bwc! If port is already specified in mResponseTarget, we
// will only override it if a port is specified in the Via.
// If mResponseTarget does _not_ have a port specified, and
// neither does the Via, we go with the default.
if(state->mResponseTarget.getPort()==0)
{
state->mResponseTarget.setPort(Helper::getPortForReply(*sip));
}
else
{
// !bwc! Do not use the default port if no port is in the Via
unsigned short port=Helper::getPortForReply(*sip,false);
if(port!=0)
{
state->mResponseTarget.setPort(port);
}
}
state->mIsReliable = state->mResponseTarget.transport->isReliable();
state->add(tid);
if (Timer::T100 == 0)
{
state->sendToWire(state->mMsgToRetransmit); // will get deleted when this is deleted
state->mState = Proceeding;
}
else
{
//StackLog(<<" adding T100 timer (INV)");
controller.mTimers.add(Timer::TimerTrying, tid, Timer::T100);
}
}
else if (sip->method() == CANCEL)
{
TransactionState* matchingInvite =
controller.mServerTransactionMap.find(sip->getTransactionId());
if (matchingInvite == 0)
{
InfoLog (<< "No matching INVITE for incoming (from wire) CANCEL to uas");
//was TransactionState::sendToTU(tu, controller, Helper::makeResponse(*sip, 481));
SipMessage* response = Helper::makeResponse(*sip, 481);
Tuple target(sip->getSource());
controller.mTransportSelector.transmit(response, target);
delete sip;
delete response;
return;
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -