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

📄 transactionstate.cxx

📁 一个著名的SIP协议栈
💻 CXX
📖 第 1 页 / 共 5 页
字号:
                  // source Tuple that the request was received on. 
                  //terminateServerTransaction(mId);
                  mMachine = ServerStale;
                  mController.mTimers.add(Timer::TimerStaleServer, mId, Timer::TS );
                  delete msg;
               }
               else
               {
                  //StackLog (<< "Received 2xx when not in Trying or Proceeding State. Ignoring");
                  delete msg;
               }
            }
            else if (code >= 300)
            {
               /*
                 While in the "Proceeding" state, if the TU passes a response with
                 status code from 300 to 699 to the server transaction, For unreliable 
                 transports,timer G is set to fire in T1 seconds, and is not set to 
                 fire for reliable transports.when the "Completed" state is entered, 
                 timer H MUST be set to fire in 64*T1 seconds for all transports.  
                 Timer H determines when the server transaction abandons retransmitting 
                 the response
               */

               if (mState == Trying || mState == Proceeding)
               {
                  StackLog (<< "Received failed response in Trying or Proceeding. Start Timer H, move to completed." << *this);
                  delete mMsgToRetransmit; 
                  mMsgToRetransmit = sip; 
                  mState = Completed;
                  try
                  {
                     if (sip->header(h_To).exists(p_tag))
                     {
                        mToTag = sip->header(h_To).param(p_tag);
                     }
                  }
                  catch(resip::ParseBuffer::Exception&)
                  {
                     // !bwc! We are only storing this To tag in order to help 
                     // distinguish ACK/failure from ACK/200 with the same tid
                     // as the original invite (a common bug in UACs). Since
                     // we technically shouldn't be doing this, we ignore the
                     // malformed To header.
                  }
                  
                  mController.mTimers.add(Timer::TimerH, mId, Timer::TH );
                  if (!mIsReliable)
                  {
                     mController.mTimers.add(Timer::TimerG, mId, Timer::T1 );
                  }
                  sendToWire(msg); // don't delete msg
               }
               else
               {
                  //StackLog (<< "Received Final response when not in Trying or Proceeding State. Ignoring");
                  delete msg;
               }
            }
            else
            {
               //StackLog (<< "Received Invalid response line. Ignoring");
               delete msg;
            }
            break;
            
         case CANCEL:
            assert(0);
            break;
            
         default:
            //StackLog (<< "Received response to non invite or cancel. Ignoring");
            delete msg;
            break;
      }
   }
   else if (isTimer(msg))
   {
      TimerMessage* timer = dynamic_cast<TimerMessage*>(msg);
      switch (timer->getType())
      {
         case Timer::TimerG:
            if (mState == Completed)
            {
               StackLog (<< "TimerG fired. retransmit, and re-add TimerG");
               sendToWire(mMsgToRetransmit, true);
               mController.mTimers.add(Timer::TimerG, mId, resipMin(Timer::T2, timer->getDuration()*2) );  //  TimerG is supposed to double - up until a max of T2 RFC3261 17.2.1
            }
            break;

            /*
              If timer H fires while in the "Completed" state, it implies that the
              ACK was never received.  In this case, the server transaction MUST
              transition to the "Terminated" state, and MUST indicate to the TU
              that a transaction failure has occurred. WHY we need to inform TU
              for Failure cases ACK ? do we really need to do this ???       

              !jf! this used to re-add TimerH if there was an associated CANCEL
              transaction. Don't know why. 
            */
         case Timer::TimerH:
         case Timer::TimerI:
            if (timer->getType() == Timer::TimerH)
            {
               InfoLog (<< "No ACK was received on a server transaction (Timer H)");
            }
            terminateServerTransaction(mId);
            delete this;
            break;

         case Timer::TimerTrying:
            if (mState == Trying)
            {
               //StackLog (<< "TimerTrying fired. Send a 100");
               sendToWire(mMsgToRetransmit); // will get deleted when this is deleted
               mState = Proceeding;
            }
            else
            {
               //StackLog (<< "TimerTrying fired. Not in Trying state. Ignoring");
            }
            break;
            
         default:
            CritLog(<<"unexpected timer fired: " << timer->getType());
            assert(0); // programming error if any other timer fires
            break;
      }
      delete timer;
   }
   else if (isTransportError(msg))
   {
      processTransportFailure(msg);
      delete msg;
   }
   else
   {
      //StackLog (<< "TransactionState::processServerInvite: message unhandled");
      delete msg;
   }
}


void
TransactionState::processClientStale(TransactionMessage* msg)
{
   StackLog (<< "TransactionState::processClientStale: " << msg->brief());

   if (isTimer(msg))
   {
      TimerMessage* timer = dynamic_cast<TimerMessage*>(msg);
      if (timer->getType() == Timer::TimerStaleClient)
      {
         terminateClientTransaction(mId);
         delete this;
         delete msg;
      }
      else
      {
         delete msg;
      }
   }
   else if (isTransportError(msg))
   {
      WarningLog (<< "Got a transport error in Stale Client state");
      StackLog (<< *this);
      processTransportFailure(msg);
      delete msg;
   }
   else
   {
      if(isResponse(msg, 200, 299))
      {
         assert(isFromWire(msg));
         sendToTU(msg);
      }
      else
      {
         // might have received some other response because a downstream UAS is
         // misbehaving. For instance, sending a 487/INVITE after already
         // sending a 200/INVITE. In this case, discard the response
         StackLog (<< "Discarding extra response: " << *msg);
         delete msg;
      }
   }
}

void
TransactionState::processServerStale(TransactionMessage* msg)
{
   StackLog (<< "TransactionState::processServerStale: " << msg->brief());

   SipMessage* sip = dynamic_cast<SipMessage*>(msg);
   if (isTimer(msg))
   {
      TimerMessage* timer = dynamic_cast<TimerMessage*>(msg);
      if (timer->getType() == Timer::TimerStaleServer)
      {
         delete msg;
         terminateServerTransaction(mId);
         delete this;
      }
      else
      {
         delete msg;
      }
   }
   else if (isTransportError(msg))
   {
      WarningLog (<< "Got a transport error in Stale Server state");
      StackLog (<< *this);
      processTransportFailure(msg);
      delete msg;
   }
   else if (sip && isRequest(sip) && sip->method() == ACK)
   {
      // this can happen when an upstream UAC sends an ACK with no to-tag when
      // it should
      assert(isFromWire(msg));
      InfoLog (<< "Passing ACK directly to TU: " << sip->brief());
      sendToTU(msg);
   }
   else if (sip && isRequest(sip) && sip->method() == INVITE)
   {
      // this can happen when an upstream UAC never received the 200 and
      // retransmits the INVITE when using unreliable transport
      // Drop the INVITE since the 200 will get retransmitted by the downstream UAS
      StackLog (<< "Dropping retransmitted INVITE in stale server transaction" << sip->brief());
      delete msg;
   }
   else if (isResponse(msg) && isFromTU(msg))
   {
      sendToWire(msg); 
      delete msg;
   }
   else
   {
      ErrLog(<<"ServerStale unexpected condition, dropping message.");
      if (sip)
      {
         ErrLog(<<sip->brief());
      }
      delete msg;
   }
}


void
TransactionState::processNoDnsResults()
{
   InfoLog (<< "Ran out of dns entries for " << mDnsResult->target() << ". Send 503");
   assert(mDnsResult->available() == DnsResult::Finished);
   SipMessage* response = Helper::makeResponse(*mMsgToRetransmit, 503);
   WarningCategory warning;
   warning.hostname() = DnsUtil::getLocalHostName();
   warning.code() = 499;
   switch(mFailureReason)
   {
      warning.text() = "No other DNS entries to try";
      case TransportFailure::None:
      case TransportFailure::Failure:
         break;
      case TransportFailure::NoTransport:
         response->header(h_StatusLine).reason() = "No matching transport found";
         break;
      case TransportFailure::NoRoute:
         response->header(h_StatusLine).reason() = "No route to host";
         break;
      case TransportFailure::CertNameMismatch:
         response->header(h_StatusLine).reason() = "Certificate Name Mismatch";
         break;
      case TransportFailure::CertValidationFailure:
         response->header(h_StatusLine).reason() = "Certificate Validation Failure";
   }
         
   response->header(h_Warnings).push_back(warning);

   sendToTU(response); // !jf! should be 480? 
   terminateClientTransaction(mId);
   if (mMachine != Stateless)
   {
	   delete this; 
   }
}

void
TransactionState::processTransportFailure(TransactionMessage* msg)
{
   TransportFailure* failure = dynamic_cast<TransportFailure*>(msg);
   assert(failure);
   
   InfoLog (<< "Try sending request to a different dns result");
   assert(mMsgToRetransmit);
   if (failure->getFailureReason() > mFailureReason)
   {
      mFailureReason = failure->getFailureReason();
   }
   
   if (mMsgToRetransmit->isRequest() && mMsgToRetransmit->method() == CANCEL)
   {
      WarningLog (<< "Failed to deliver a CANCEL request");
      StackLog (<< *this);
      assert(mIsCancel);

      // In the case of a client-initiated CANCEL, we don't want to
      // try other transports in the case of transport error as the
      // CANCEL MUST be sent to the same IP/PORT as the orig. INVITE.
      //?dcm? insepct failure enum?
      SipMessage* response = Helper::makeResponse(*mMsgToRetransmit, 503);
      WarningCategory warning;
      warning.hostname() = DnsUtil::getLocalHostName();
      warning.code() = 499;
      warning.text() = "Failed to deliver CANCEL using the same transport as the INVITE was used";
      response->header(h_Warnings).push_back(warning);
      
      sendToTU(response);
      return;
   }

   assert(!mIsCancel);
   if (mDnsResult)
   {
      switch (mDnsResult->available())
      {
         case DnsResult::Available:
            mMsgToRetransmit->header(h_Vias).front().param(p_branch).incrementTransportSequence();
            mTarget = mDnsResult->next();
            processReliability(mTarget.getType());
            sendToWire(mMsgToRetransmit);
            break;
         
         case DnsResult::Pending:
            mMsgToRetransmit->header(h_Vias).front().param(p_branch).incrementTransportSequence();
            break;

         case DnsResult::Finished:
            processNoDnsResults();
            break;

         case DnsResult::Destroyed:
         default:
            InfoLog (<< "Bad state: " << *this);
            assert(0);
      }
   }
}

// called by DnsResult
void
TransactionState::rewriteRequest(const Uri& rewrite)
{
   assert(mMsgToRetransmit->isRequest());
   if (mMsgToRetransmit->header(h_RequestLine).uri() != rewrite)
   {
      InfoLog (<< "Rewriting request-uri to " << rewrite);
      mMsgToRetransmit->header(h_RequestLine).uri() = rewrite;
   }
}

void 
TransactionState::handle(DnsResult* result)
{
   // got a DNS response, so send the current message
   StackLog (<< *this << " got DNS result: " << *result);
   
   if (mTarget.getType() == UNKNOWN_TRANSPORT) 
   {
      assert(mDnsResult);
      switch (mDnsResult->available())
      {
         case DnsResult::Available:
            mTarget = mDnsResult->next();
            processReliability(mTarget.getType());
            mController.mTransportSelector.transmit(mMsgToRetransmit, mTarget);
            break;
            
         case DnsResult::Finished:
            processNoDnsResults();
            break;

         case DnsResult::Pending:
            break;
            
         case DnsResult::Destroyed:
         default:
            assert(0);
            break;
      }
   }
   else

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -