📄 transactionstate.cxx
字号:
// !bwc! // An interesting consequence occurs if our failover ultimately // sends to the same instance of a resip stack; we increment the // transport sequence in our branch parameter, but any resip-based // stack will ignore this change, and process this "new" request as // a retransmission! Furthermore, our state will be out of phase // with the state at the remote endpoint, and if we have sent a // PRACK, it will know (and stuff will break)! // TODO What else needs to be done here to safely revert our state? mState=Calling; } shouldFailover=true; } } if(mDnsResult) { // .bwc. Greylist for 32s // !bwc! TODO make this duration configurable. mDnsResult->greylistLast(Timer::getTimeMs()+32000); } if(shouldFailover) { 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: restoreOriginalContactAndVia(); mTarget = mDnsResult->next(); processReliability(mTarget.getType()); sendToWire(mMsgToRetransmit); break; case DnsResult::Pending: mWaitingForDnsResult=true; restoreOriginalContactAndVia(); break; case DnsResult::Finished: processNoDnsResults(); break; case DnsResult::Destroyed: default: InfoLog (<< "Bad state: " << *this); assert(0); } } }}// called by DnsResultvoidTransactionState::rewriteRequest(const Uri& rewrite){ // !bwc! TODO We need to address the race-conditions caused by callbacks // into a class whose thread-safety is accomplished through message-passing. // This function could very easily be called while other processing is // taking place due to a message from the state-machine fifo. In the end, I // imagine that we will need to have the callback place a message onto the // queue, and move all the code below into a function that handles that // message. 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){ // !bwc! TODO We need to address the race-conditions caused by callbacks // into a class whose thread-safety is accomplished through message-passing. // This function could very easily be called while other processing is // taking place due to a message from the state-machine fifo. In the end, I // imagine that we will need to have the callback place a message onto the // queue, and move all the code below into a function that handles that // message. // got a DNS response, so send the current message StackLog (<< *this << " got DNS result: " << *result); // .bwc. Were we expecting something from mDnsResult? if (mWaitingForDnsResult) { assert(mDnsResult); switch (mDnsResult->available()) { case DnsResult::Available: mWaitingForDnsResult=false; mTarget = mDnsResult->next(); processReliability(mTarget.getType()); mController.mTransportSelector.transmit(mMsgToRetransmit, mTarget); break; case DnsResult::Finished: mWaitingForDnsResult=false; processNoDnsResults(); break; case DnsResult::Pending: break; case DnsResult::Destroyed: default: assert(0); break; } }}voidTransactionState::processReliability(TransportType type){ switch (type) { case UDP: case DCCP: if (mIsReliable) { mIsReliable = false; StackLog (<< "Unreliable transport: " << *this); switch (mMachine) { case ClientNonInvite: mController.mTimers.add(Timer::TimerE1, mId, Timer::T1 ); break; case ClientInvite: mController.mTimers.add(Timer::TimerA, mId, Timer::T1 ); break; default: break; } } break; default: if (!mIsReliable) { mIsReliable = true; } break; }}// !ah! only used one place, so leaving it here instead of making a helper.// !ah! broken out for clarity -- only used for forceTargets.// Expects that host portion is IP address notation.static const TuplesimpleTupleForUri(const Uri& uri){ const Data& host = uri.host(); int port = uri.port(); resip::TransportType transport = UNKNOWN_TRANSPORT; if (uri.exists(p_transport)) { transport = Tuple::toTransport(uri.param(p_transport)); } if (transport == UNKNOWN_TRANSPORT) { transport = UDP; } if (port == 0) { switch(transport) { case TLS: port = Symbols::DefaultSipsPort; break; case UDP: case TCP: default: port = Symbols::DefaultSipPort; break; // !ah! SCTP? } } return Tuple(host,port,transport);}voidTransactionState::sendToWire(TransactionMessage* msg, bool resend) { SipMessage* sip = dynamic_cast<SipMessage*>(msg); if (!sip) { CritLog(<<"sendToWire: message not a sip message at address " << (void*)msg); assert(sip); return; } if(mController.mStack.statisticsManagerEnabled()) { mController.mStatsManager.sent(sip, resend); } // !jf! for responses, go back to source always (not RFC exactly) if (mMachine == ServerNonInvite || mMachine == ServerInvite || mMachine == ServerStale) { assert(mDnsResult == 0); assert(sip->exists(h_Vias)); assert(!sip->header(h_Vias).empty()); Tuple target(mResponseTarget); if (sip->hasForceTarget()) { target = simpleTupleForUri(sip->getForceTarget()); StackLog(<<"!ah! response with force target going to : "<<target); } else if (sip->header(h_Vias).front().exists(p_rport) && sip->header(h_Vias).front().param(p_rport).hasValue()) { target.setPort(sip->header(h_Vias).front().param(p_rport).port()); StackLog(<< "rport present in response, sending to " << target); } else { StackLog(<< "tid=" << sip->getTransactionId() << " sending to : " << target); } if (resend) { mController.mTransportSelector.retransmit(sip, target); } else { mController.mTransportSelector.transmit(sip, target); } } else if (sip->getDestination().mFlowKey || mTarget.mFlowKey) { if (resend) { if (mTarget.transport) { mController.mTransportSelector.retransmit(sip, mTarget); } else { DebugLog (<< "No transport found(network could be down) for " << sip->brief()); } } else { // !bwc! We have the FlowKey. This completely specifies our Transport // (and Connection, if applicable) if(!mTarget.mFlowKey) { DebugLog(<< "Sending to tuple: " << sip->getDestination()); mTarget = sip->getDestination(); processReliability(mTarget.getType()); } mController.mTransportSelector.transmit(sip, mTarget); // dns not used } } else if (mDnsResult == 0 && !mIsCancel) // no dns query yet { StackLog (<< "sendToWire with no dns result: " << *this); assert(sip->isRequest()); assert(!mIsCancel); mDnsResult = mController.mTransportSelector.createDnsResult(this); mWaitingForDnsResult=true; mController.mTransportSelector.dnsResolve(mDnsResult, sip); } else // reuse the last dns tuple { assert(sip->isRequest()); if(mTarget.getType() != UNKNOWN_TRANSPORT) { if (resend) { if (mTarget.transport) { mController.mTransportSelector.retransmit(sip, mTarget); } else { DebugLog (<< "No transport found(network could be down) for " << sip->brief()); } } else { mController.mTransportSelector.transmit(sip, mTarget); } } else { // .bwc. While the resolver was attempting to find a target, another // request came down from the TU. This could be a bug in the TU, or // could be a retransmission of an ACK/200. Either way, we cannot // expect to ever be able to send this request (nowhere to store it // temporarily). DebugLog(<< "Received a second request from the TU for a transaction" " that already existed, before the DNS subsystem was done " "resolving the target for the first request. Either the TU" " has messed up, or it is retransmitting ACK/200 (the only" " valid case for this to happen)"); } }}voidTransactionState::sendToTU(TransactionMessage* msg) const{ SipMessage* sipMsg = dynamic_cast<SipMessage*>(msg); if (sipMsg && sipMsg->isResponse() && mDnsResult) { // whitelisting rules. switch (sipMsg->header(h_StatusLine).statusCode()) { case 503: // blacklist last target. // .bwc. If there is no Retry-After, we do not blacklist // (see RFC 3261 sec 21.5.4 para 1) if(sipMsg->exists(resip::h_RetryAfter) && sipMsg->header(resip::h_RetryAfter).isWellFormed()) { unsigned int relativeExpiry= sipMsg->header(resip::h_RetryAfter).value(); mDnsResult->blacklistLast(resip::Timer::getTimeMs()+relativeExpiry*1000); } break; case 408: if(sipMsg->getReceivedTransport() == 0 && (mState == Trying || mState==Calling)) // only greylist if internally generated and we haven't received any responses yet { // greylist last target. // ?bwc? How long do we greylist this for? Probably should make // this configurable. TODO mDnsResult->greylistLast(resip::Timer::getTimeMs() + 32000); } break; default: // !bwc! Debatable. mDnsResult->whitelistLast(); break; } } TransactionState::sendToTU(mTransactionUser, mController, msg);}voidTransactionState::sendToTU(TransactionUser* tu, TransactionController& controller, TransactionMessage* msg) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -