⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 transactionstate.cxx

📁 一个著名的SIP协议栈
💻 CXX
📖 第 1 页 / 共 5 页
字号:
#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 + -