📄 transactionstate.cxx
字号:
// 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 // since we don't want to reply to the source port if rport present state->mResponseTarget.setPort(Helper::getPortForReply(*sip)); state->mIsReliable = isReliable(state->mResponseTarget.getType()); 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 { 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 if rport present state->mResponseTarget.setPort(Helper::getPortForReply(*sip)); state->add(tid); state->mIsReliable = isReliable(state->mResponseTarget.getType()); 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)); matchingInvite->terminateClientTransaction(matchingInvite->mId); 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->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; }}voidTransactionState::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}voidTransactionState::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::saveOriginalContactAndVia(const SipMessage& sip){ if(sip.exists(h_Contacts) && sip.header(h_Contacts).size() == 1) { mOriginalContact = std::auto_ptr<NameAddr>(new NameAddr(sip.header(h_Contacts).front())); } mOriginalVia = std::auto_ptr<Via>(new Via(sip.header(h_Vias).front()));}void TransactionState::restoreOriginalContactAndVia(){ if (mOriginalContact.get()) { mMsgToRetransmit->header(h_Contacts).front() = *mOriginalContact; } if (mOriginalVia.get()) { mOriginalVia->param(p_branch).incrementTransportSequence(); mMsgToRetransmit->header(h_Vias).front() = *mOriginalVia; }}voidTransactionState::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; saveOriginalContactAndVia(*sip); 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; }}voidTransactionState::processClientInvite(TransactionMessage* msg){ StackLog(<< "TransactionState::processClientInvite: " << msg->brief() << " " << *this); if (isRequest(msg) && isFromTU(msg)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -