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

📄 transactionstate.cxx

📁 一个著名的SIP协议栈
💻 CXX
📖 第 1 页 / 共 5 页
字号:
               {
                  assert(matchingInvite);
                  state = TransactionState::makeCancelTransaction(matchingInvite, ServerNonInvite, tid);
                  state->startServerNonInviteTimerTrying(*sip,tid);
               }
            }
            else if (sip->method() != ACK)
            {
               TransactionState* state = new TransactionState(controller, ServerNonInvite,Trying, tid, tu);
               state->mResponseTarget = sip->getSource();
               // since we don't want to reply to the source port unless rport present 
               state->mResponseTarget.setPort(Helper::getPortForReply(*sip));
               state->add(tid);
               state->mIsReliable = state->mResponseTarget.transport->isReliable();
               state->startServerNonInviteTimerTrying(*sip,tid);
            }
            
            // Incoming ACK just gets passed to the TU
            //StackLog(<< "Adding incoming message to TU fifo " << tid);
            TransactionState::sendToTU(tu, controller, sip);
         }
         else // new sip msg from the TU
         {
            if (sip->method() == INVITE)
            {
               TransactionState* state = new TransactionState(controller, ClientInvite, Calling, tid, tu);
               state->add(state->mId);
               state->processClientInvite(sip);
            }
            else if (sip->method() == ACK)
            {
               //TransactionState* state = new TransactionState(controller, Stateless, Calling, Data(StatelessIdCounter++));
               TransactionState* state = new TransactionState(controller, Stateless, Calling, tid, tu);
               state->add(state->mId);
               state->mController.mTimers.add(Timer::TimerStateless, state->mId, Timer::TS );
               state->processStateless(sip);
            }
            else if (sip->method() == CANCEL)
            {
               TransactionState* matchingInvite = controller.mClientTransactionMap.find(sip->getTransactionId());
               if (matchingInvite == 0)
               {
                  InfoLog (<< "No matching INVITE for incoming (from TU) CANCEL to uac");
                  TransactionState::sendToTU(tu, controller, Helper::makeResponse(*sip,481));
                  delete sip;
               }
               else if (matchingInvite->mState == Calling) // CANCEL before 1xx received
               {
                  WarningLog(<< "You can't CANCEL a request until a provisional has been received");
                  StackLog (<< *matchingInvite);
                  StackLog (<< *sip);

                  // if no INVITE had been sent out yet. -- i.e. dns result not
                  // processed yet 

                  // The CANCEL was received before the INVITE was sent
                  // This can happen in odd cases. Too common to assert.
                  // Be graceful.
                  TransactionState::sendToTU(tu, controller, Helper::makeResponse(*sip, 200));
                  matchingInvite->sendToTU(Helper::makeResponse(*matchingInvite->mMsgToRetransmit, 487));

                  delete matchingInvite;
                  delete sip;

               }
               else if (matchingInvite->mState == Completed)
               {
                  // A final response was already seen for this INVITE transaction
                  matchingInvite->sendToTU(Helper::makeResponse(*sip, 200));
                  delete sip;
               }
               else
               {
                  assert(matchingInvite);
                  state = TransactionState::makeCancelTransaction(matchingInvite, ClientNonInvite, tid);
                  //state->processReliability(matchingInvite->mTarget.getType());  // !slg! Not needed - timer started in makeCancelTransaction
                  state->processClientNonInvite(sip);
                  
                  // for the INVITE in case we never get a 487
                  matchingInvite->mController.mTimers.add(Timer::TimerCleanUp, sip->getTransactionId(), 128*Timer::T1);
               }
            }
            else 
            {
               TransactionState* state = new TransactionState(controller, ClientNonInvite, 
                                                              Trying, tid, tu);
               state->add(tid);
               state->processClientNonInvite(sip);
            }
         }
      }
      else if (sip->isResponse()) // stray response
      {
         if (controller.mDiscardStrayResponses)
         {
            InfoLog (<< "discarding stray response: " << sip->brief());
            delete message;
         }
         else
         {
            StackLog (<< "forwarding stateless response: " << sip->brief());
            TransactionState* state = 
               new TransactionState(controller, Stateless, Calling, 
                                    Data(StatelessIdCounter++), tu);
            state->add(state->mId);
            state->mController.mTimers.add(Timer::TimerStateless, state->mId, Timer::TS );
            state->processStateless(sip);
         }
      }
      else // wasn't a request or a response
      {
         //StackLog (<< "discarding unknown message: " << sip->brief());
      }
   } 
   else // timer or other non-sip msg
   {
      //StackLog (<< "discarding non-sip message: " << message->brief());
      delete message;
   }
}

void
TransactionState::startServerNonInviteTimerTrying(SipMessage& sip, Data& tid)
{
   unsigned int duration = 3500;
   if(Timer::T1 != 500) // optimzed for T1 == 500
   {
      // Iteratively calculate how much time before TimerE reaches T2 (RFC4320) - could be improved
      duration = Timer::T1;
      while(duration*2<Timer::T2) duration = duration * 2;
   }
   mMsgToRetransmit = make100(&sip);  // Store for use when timer expires
   mController.mTimers.add(Timer::TimerTrying, tid, duration );  // Start trying timer so that we can send 100 to NITs as recommened in RFC4320
}

void
TransactionState::processStateless(TransactionMessage* message)
{
   // for ACK messages from the TU, there is no transaction, send it directly
   // to the wire // rfc3261 17.1 Client Transaction
   SipMessage* sip = dynamic_cast<SipMessage*>(message);
   StackLog (<< "TransactionState::processStateless: " << message->brief());
   
   // !jf! There is a leak for Stateless transactions associated with ACK to 200
   if (isFromTU(message))
   {
      delete mMsgToRetransmit;
      mMsgToRetransmit = sip;
      sendToWire(sip);
   }
   else if (isFromWire(message))
   {
      InfoLog (<< "Received message from wire on a stateless transaction");
      StackLog (<< *message);
      //assert(0);
      sendToTU(sip);
   }
   else if (isTransportError(message))
   {
      processTransportFailure(message);
      
      delete message;
      delete this;
   }
   else if (isTimer(message))
   {
      TimerMessage* timer = dynamic_cast<TimerMessage*>(message);
      if (timer->getType() == Timer::TimerStateless)
      {
         delete message;
         delete this;
      }
   }
   else
   {
      assert(0);
   }
}

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

   assert(!isInvite(msg));

   if (isRequest(msg) && isFromTU(msg))
   {
      //StackLog (<< "received new non-invite request");
      SipMessage* sip = dynamic_cast<SipMessage*>(msg);
      delete mMsgToRetransmit;
      mMsgToRetransmit = sip;
      mController.mTimers.add(Timer::TimerF, mId, Timer::TF);
      sendToWire(sip);  // don't delete
   }
   else if (isResponse(msg) && isFromWire(msg)) // from the wire
   {
      //StackLog (<< "received response from wire");

      SipMessage* sip = dynamic_cast<SipMessage*>(msg);
      int code = sip->header(h_StatusLine).responseCode();
      if (code >= 100 && code < 200) // 1XX
      {
         if (mState == Trying || mState == Proceeding)
         {
            //?slg? if we set the timer in Proceeding, then every 1xx response will cause another TimerE2 to be set and many retransmissions will occur - which is not correct
            // Should we restart the E2 timer though?  If so, we need to use somekind of timer sequence number so that previous E2 timers get discarded.
            if (!mIsReliable && mState == Trying)
            {
               mController.mTimers.add(Timer::TimerE2, mId, Timer::T2 );
            }
            mState = Proceeding;
            sendToTU(msg); // don't delete            
         }
         else
         {
            // ignore
            delete msg;
         }
      }
      else if (code >= 200)
      {
         // don't notify the TU of retransmissions
         if (mState == Trying || mState == Proceeding)
         {
            sendToTU(msg); // don't delete
         }
         else if (mState == Completed)
         {
            delete msg;
         }
         
         if (mIsReliable)
         {
            terminateClientTransaction(mId);
            delete this;
         }
         else if (mState != Completed) // prevent TimerK reproduced
         {
            mState = Completed;
            mController.mTimers.add(Timer::TimerK, mId, Timer::T4 );            
         }
      }
   }
   else if (isTimer(msg))
   {
      //StackLog (<< "received timer in client non-invite transaction");

      TimerMessage* timer = dynamic_cast<TimerMessage*>(msg);
      switch (timer->getType())
      {
         case Timer::TimerE1:
            if (mState == Trying)
            {
               unsigned long d = timer->getDuration();
               if (d < Timer::T2) d *= 2;
               mController.mTimers.add(Timer::TimerE1, mId, d);
               StackLog (<< "Retransmitting: " << mMsgToRetransmit->brief());
               sendToWire(mMsgToRetransmit, true);
               delete msg;
            }
            else
            {
               // ignore
               delete msg;
            }
            break;

         case Timer::TimerE2:
            if (mState == Proceeding)
            {
               mController.mTimers.add(Timer::TimerE2, mId, Timer::T2);
               StackLog (<< "Retransmitting: " << mMsgToRetransmit->brief());
               sendToWire(mMsgToRetransmit, true);
               delete msg;
            }
            else 
            {
               // ignore
               delete msg;
            }
            break;

         case Timer::TimerF:
            if (mState == Trying || mState == Proceeding)
            {
               sendToTU(Helper::makeResponse(*mMsgToRetransmit, 408));
               terminateClientTransaction(mId);
               delete this;
            }
            
            delete msg;
            break;

         case Timer::TimerK:
            terminateClientTransaction(mId);
            delete msg;
            delete this;
            break;

         default:
            //InfoLog (<< "Ignoring timer: " << *msg);
            delete msg;
            break;
      }
   }
   else if (isTransportError(msg))
   {
      processTransportFailure(msg);
      delete msg;
   }
   else
   {
      //StackLog (<< "TransactionState::processClientNonInvite: message unhandled");
      delete msg;
   }
}

void
TransactionState::processClientInvite(TransactionMessage* msg)
{
   StackLog(<< "TransactionState::processClientInvite: " << msg->brief() << " " << *this);
   if (isRequest(msg) && isFromTU(msg))
   {
      SipMessage* sip = dynamic_cast<SipMessage*>(msg);
      switch (sip->method())
      {
         // Received INVITE request from TU="Transaction User", Start Timer B which controls
         // transaction timeouts. 
         case INVITE:
            delete mMsgToRetransmit; 
            mMsgToRetransmit = sip;
            mController.mTimers.add(Timer::TimerB, mId, Timer::TB);
            sendToWire(msg); // don't delete msg
            break;
            
         case CANCEL:
            assert(0);
            break;

         default:
            delete msg;
            break;
      }
   }
   else if (isResponse(msg) && isFromWire(msg))
   {
      SipMessage* sip = dynamic_cast<SipMessage*>(msg);
      int code = sip->header(h_StatusLine).responseCode();
      switch (sip->method())
      {
         case INVITE:
            /* If the client transaction receives a provisional response while in
               the "Calling" state, it transitions to the "Proceeding" state. In the
               "Proceeding" state, the client transaction SHOULD NOT retransmit the
               request any longer (this will be Handled in  "else if (isTimer(msg))")
               The Retransmissions will be stopped, Not by Cancelling Timers but
               by Ignoring the fired Timers depending upon the State which stack is in.   
            */
            if (code >= 100 && code < 200) // 1XX
            {
               if (mState == Calling || mState == Proceeding)
               {
                  mState = Proceeding;
                  sendToTU(sip); // don't delete msg
               }
               else
               {
                  delete msg;
               }
            }

            /* When in either the "Calling" or "Proceeding" states, reception of a
               2xx response MUST cause the client transaction to enter the
               "Terminated" state, and the response MUST be passed up to the TU 
               State Machine is changed to Stale since, we wanted to ensure that 
               all 2xx gets to TU
            */
            else if (code >= 200 && code < 300)
            {
               sendToTU(sip); // don't delete msg
               //terminateClientTransaction(mId);
               mMachine = ClientStale;
               StackLog (<< "Received 2xx on client invite transaction");
               StackLog (<< *this);
               mController.mTimers.add(Timer::TimerStaleClient, mId, Timer::TS );
            }
            else if (code >= 300)
            {
               // When in either the "Calling" or "Proceeding" states, reception of a

⌨️ 快捷键说明

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