📄 transactionstate.cxx
字号:
} } else { //StackLog (<< "Ignore ACK not in Completed state"); delete msg; } break; case CANCEL: assert(0); break; default: //StackLog (<< "Received unexpected request. Ignoring message"); delete msg; break; } } else if (isResponse(msg, 100, 699) && isFromTU(msg)) { SipMessage* sip = dynamic_cast<SipMessage*>(msg); int code = sip->header(h_StatusLine).responseCode(); switch (sip->method()) { case INVITE: if (code == 100) { if (mState == Trying || mState == Proceeding) { //StackLog (<< "Received 100 in Trying or Proceeding. Send over wire"); delete mMsgToRetransmit; // may be replacing the 100 mMsgToRetransmit = sip; mState = Proceeding; sendToWire(msg); // don't delete msg } else { //StackLog (<< "Ignoring 100 - not in Trying or Proceeding."); delete msg; } } else if (code > 100 && code < 200) { if (mState == Trying || mState == Proceeding) { //StackLog (<< "Received 1xx in Trying or Proceeding. Send over wire"); delete mMsgToRetransmit; // may be replacing the 100 mMsgToRetransmit = sip; mState = Proceeding; sendToWire(msg); // don't delete msg } else { //StackLog (<< "Received 100 when not in Trying State. Ignoring"); delete msg; } } else if (code >= 200 && code < 300) { if (mState == Trying || mState == Proceeding) { StackLog (<< "Received 2xx when in Trying or Proceeding State of server invite transaction"); StackLog (<< *this); sendToWire(msg); // Keep the StaleServer transaction around, so we can keep the // 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) { mAckIsValid=true; StackLog (<< "Received failed response in Trying or Proceeding. Start Timer H, move to completed." << *this); delete mMsgToRetransmit; mMsgToRetransmit = sip; mState = Completed; 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; }}voidTransactionState::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; } }}voidTransactionState::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) { // .bwc. We should never fall into this block. There is code in process // that should prevent it. 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 { // .bwc. This can very easily be triggered by a stupid/malicious // endpoint. This is not an error in our code. Do not ErrLog this. InfoLog(<<"ServerStale unexpected condition, dropping message."); if (sip) { InfoLog(<<sip->brief()); } delete msg; }}voidTransactionState::processNoDnsResults(){ if(mMsgToRetransmit->method()==ACK) { // Don't 503 a failed ACK return; } 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; }}voidTransactionState::processTransportFailure(TransactionMessage* msg){ TransportFailure* failure = dynamic_cast<TransportFailure*>(msg); assert(failure); assert(mState!=Bogus); // .bwc. We should only try multiple dns results if we are originating a // request. Additionally, there are (potential) cases where it would not // be appropriate to fail over even then. bool shouldFailover=false; if(mMachine==ClientNonInvite) { if(mState==Completed || mState==Terminated) { WarningLog(<<"Got a TransportFailure message in a " << mState << " ClientNonInvite transaction. How did this happen? Since we have" " already completed the transaction, we shouldn't try" " additional DNS results."); } else { shouldFailover=true; } } else if(mMachine==ClientInvite) { if(mState==Completed || mState==Terminated) { // .bwc. Perhaps the attempted transmission of the ACK failed here. // (assuming this transaction got a failure response; not sure what // might have happened if this is not the case) // In any case, we should not try sending the INVITE anywhere else. InfoLog(<<"Got a TransportFailure message in a " << mState << " ClientInvite transaction. Since we have" " already completed the transaction, we shouldn't try" " additional DNS results."); } else { if(mState==Proceeding) { // .bwc. We need to revert our state back to Calling, since we are // going to be sending the INVITE to a new endpoint entirely.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -