reSIProcate/repro  9694
ResponseContext.cxx
Go to the documentation of this file.
00001 #if defined(HAVE_CONFIG_H)
00002 #include "config.h"
00003 #endif
00004 
00005 #include <iostream>
00006 
00007 #include "resip/stack/ExtensionParameter.hxx"
00008 #include "resip/stack/InteropHelper.hxx"
00009 #include "resip/stack/SipMessage.hxx"
00010 #include "resip/stack/SipStack.hxx"
00011 #include "rutil/DnsUtil.hxx"
00012 #include "rutil/Inserter.hxx"
00013 #include "resip/stack/Helper.hxx"
00014 #include "rutil/Logger.hxx"
00015 #include "repro/Proxy.hxx"
00016 #include "repro/ResponseContext.hxx"
00017 #include "repro/RequestContext.hxx"
00018 #include "repro/RRDecorator.hxx"
00019 #include "repro/Ack200DoneMessage.hxx"
00020 #include "rutil/WinLeakCheck.hxx"
00021 
00022 #define RESIPROCATE_SUBSYSTEM resip::Subsystem::REPRO
00023 
00024 using namespace resip;
00025 using namespace repro;
00026 using namespace std;
00027 
00028 ResponseContext::ResponseContext(RequestContext& context) : 
00029    mRequestContext(context),
00030    mBestPriority(50),
00031    mSecure(false), //context.getOriginalRequest().header(h_RequestLine).uri().scheme() == Symbols::Sips)
00032    mIsClientBehindNAT(false)
00033 {
00034 }
00035 
00036 
00037 ResponseContext::~ResponseContext()
00038 {
00039    TransactionMap::iterator i;
00040    
00041    for(i=mTerminatedTransactionMap.begin(); i!=mTerminatedTransactionMap.end();++i)
00042    {
00043       delete i->second;
00044    }
00045    mTerminatedTransactionMap.clear();
00046    
00047    for(i=mActiveTransactionMap.begin(); i!=mActiveTransactionMap.end();++i)
00048    {
00049       delete i->second;
00050    }
00051    mActiveTransactionMap.clear();
00052    
00053    for(i=mCandidateTransactionMap.begin(); i!=mCandidateTransactionMap.end();++i)
00054    {
00055       delete i->second;
00056    }
00057    mCandidateTransactionMap.clear();
00058 }
00059 
00060 resip::Data
00061 ResponseContext::addTarget(const NameAddr& addr, bool beginImmediately)
00062 {
00063    InfoLog (<< "Adding candidate " << addr);
00064    std::auto_ptr<Target> target(new Target(addr));
00065    Data tid=target->tid();
00066    addTarget(target, beginImmediately);
00067    return tid;
00068 }
00069 
00070 bool
00071 ResponseContext::addTarget(std::auto_ptr<repro::Target> target, bool beginImmediately)
00072 {
00073    if(mRequestContext.mHaveSentFinalResponse || !target.get())
00074    {
00075       return false;
00076    }
00077 
00078    //Disallow sip: if secure
00079    if(mSecure && target->uri().scheme() != Symbols::Sips)
00080    {
00081       return false;
00082    }
00083    
00084    //Make sure we don't have Targets with an invalid initial state.
00085    if(target->status() != Target::Candidate)
00086    {
00087       return false;
00088    }
00089    
00090    if(beginImmediately)
00091    {
00092       if(isDuplicate(target.get()))
00093       {
00094          return false;
00095       }
00096    
00097       mTargetList.push_back(target->rec());
00098       
00099       beginClientTransaction(target.get());
00100       target->status()=Target::Started;
00101       Target* toAdd=target.release();
00102       mActiveTransactionMap[toAdd->tid()]=toAdd;
00103    }
00104    else
00105    {
00106       if(target->mShouldAutoProcess)  // note: for base repro - this is always true
00107       {
00108          std::list<resip::Data> queue;
00109          queue.push_back(target->tid());
00110          mTransactionQueueCollection.push_back(queue);
00111       }
00112 
00113       Target* toAdd=target.release();
00114       mCandidateTransactionMap[toAdd->tid()]=toAdd;
00115    }
00116    
00117    return true;
00118 }
00119 
00120 bool
00121 ResponseContext::addTargetBatch(TargetPtrList& targets,
00122                                 bool highPriority)
00123 {
00124    std::list<resip::Data> queue;
00125    Target* target=0;
00126    TargetPtrList::iterator it;
00127 
00128    if(mRequestContext.mHaveSentFinalResponse || targets.empty())
00129    {
00130       for(it=targets.begin();it!=targets.end();it++)
00131       {
00132          delete *it;
00133       }
00134       
00135       targets.clear();
00136       return false;
00137    }
00138 
00139    for(it=targets.begin();it!=targets.end();it++)
00140    {
00141       target=*it;
00142       
00143       if((!mSecure || target->uri().scheme() == Symbols::Sips) &&
00144          target->status() == Target::Candidate)
00145       {
00146          if(target->mShouldAutoProcess)
00147          {
00148             queue.push_back(target->tid());
00149          }
00150          DebugLog(<<"Adding Target to Candidates: " << target->uri() << " tid=" << target->tid());
00151          mCandidateTransactionMap[target->tid()]=target;
00152       }
00153       else
00154       {
00155          DebugLog(<<"Bad Target: " << target->uri());
00156          delete target;
00157       }
00158    }
00159 
00160    targets.clear();
00161    
00162    if(highPriority)  // note: for base repro - this is always false
00163    {
00164       mTransactionQueueCollection.push_front(queue);
00165    }
00166    else
00167    {
00168       mTransactionQueueCollection.push_back(queue);
00169    }
00170    
00171    return true;
00172 }
00173 
00174 bool 
00175 ResponseContext::beginClientTransactions()
00176 {
00177    bool result=false;
00178    
00179    if(mCandidateTransactionMap.empty())
00180    {
00181       return result;
00182    }
00183    
00184    for (TransactionMap::iterator i=mCandidateTransactionMap.begin(); i != mCandidateTransactionMap.end(); )
00185    {
00186       if(!isDuplicate(i->second) && !mRequestContext.mHaveSentFinalResponse)
00187       {
00188          mTargetList.push_back(i->second->rec());  // Add to Target list for future duplicate detection
00189          beginClientTransaction(i->second);
00190          result=true;
00191          // see rfc 3261 section 16.6
00192          //This code moves the Target from mCandidateTransactionMap to mActiveTransactionMap,
00193          //and begins the transaction.
00194          mActiveTransactionMap[i->second->tid()] = i->second;
00195          InfoLog (<< "Creating new client transaction " << i->second->tid() << " -> " << i->second->uri());
00196       }
00197       else
00198       {
00199          i->second->status() = Target::Terminated;
00200          mTerminatedTransactionMap[i->second->tid()] = i->second;
00201          DebugLog(<<"Found a repeated target.");
00202       }
00203       
00204       TransactionMap::iterator temp=i;
00205       i++;
00206       mCandidateTransactionMap.erase(temp);
00207    }
00208    
00209    return result;
00210 }
00211 
00212 bool 
00213 ResponseContext::beginClientTransaction(const resip::Data& tid)
00214 {
00215    TransactionMap::iterator i = mCandidateTransactionMap.find(tid);
00216    if(i==mCandidateTransactionMap.end())
00217    {
00218       return false;
00219    }
00220    
00221    if(isDuplicate(i->second) || mRequestContext.mHaveSentFinalResponse)
00222    {
00223       i->second->status() = Target::Terminated;
00224       mTerminatedTransactionMap[i->second->tid()] = i->second;
00225       mCandidateTransactionMap.erase(i);
00226       return false;
00227    }
00228    
00229    mTargetList.push_back(i->second->rec()); // Add to Target list for future duplicate detection
00230 
00231    beginClientTransaction(i->second);
00232    mActiveTransactionMap[i->second->tid()] = i->second;
00233    InfoLog(<< "Creating new client transaction " << i->second->tid() << " -> " << i->second->uri());
00234    mCandidateTransactionMap.erase(i);
00235    
00236    return true;
00237 }
00238 
00239 bool 
00240 ResponseContext::cancelActiveClientTransactions()
00241 {
00242    if(mRequestContext.mHaveSentFinalResponse)
00243    {
00244       return false;
00245    }
00246 
00247    InfoLog (<< "Cancel all proceeding client transactions: " << (mCandidateTransactionMap.size() + 
00248             mActiveTransactionMap.size()));
00249 
00250    if(mActiveTransactionMap.empty())
00251    {
00252       return false;
00253    }
00254 
00255    // CANCEL INVITE branches
00256    for (TransactionMap::iterator i = mActiveTransactionMap.begin(); 
00257         i != mActiveTransactionMap.end(); ++i)
00258    {
00259       cancelClientTransaction(i->second);
00260    }
00261       
00262    return true;
00263 
00264 }
00265 
00266 bool
00267 ResponseContext::cancelAllClientTransactions()
00268 {
00269 
00270    InfoLog (<< "Cancel ALL client transactions: " << mCandidateTransactionMap.size()
00271             << " pending, " << mActiveTransactionMap.size() << " active.");
00272 
00273    if(mActiveTransactionMap.empty() && mCandidateTransactionMap.empty())
00274    {
00275       return false;
00276    }
00277 
00278    // CANCEL INVITE branches
00279    if(mRequestContext.getOriginalRequest().method()==INVITE)
00280    {
00281       for (TransactionMap::iterator i = mActiveTransactionMap.begin(); 
00282            i != mActiveTransactionMap.end(); ++i)
00283       {
00284          cancelClientTransaction(i->second);
00285       }
00286    }
00287 
00288    clearCandidateTransactions();
00289    
00290    return true;
00291 
00292 }
00293 
00294 bool
00295 ResponseContext::clearCandidateTransactions()
00296 {
00297    bool result=false;
00298    for (TransactionMap::iterator j = mCandidateTransactionMap.begin(); 
00299         j != mCandidateTransactionMap.end();)
00300    {
00301       result=true;
00302       cancelClientTransaction(j->second);
00303       mTerminatedTransactionMap[j->second->tid()] = j->second;
00304       TransactionMap::iterator temp = j;
00305       j++;
00306       mCandidateTransactionMap.erase(temp);
00307    }
00308    
00309    return result;
00310 }
00311 
00312 bool 
00313 ResponseContext::cancelClientTransaction(const resip::Data& tid)
00314 {
00315 
00316    TransactionMap::iterator i = mActiveTransactionMap.find(tid);
00317    if(mRequestContext.getOriginalRequest().method()==INVITE)
00318    {
00319       if(i!=mActiveTransactionMap.end())
00320       {
00321          cancelClientTransaction(i->second);      
00322          return true;
00323       }
00324    }
00325    
00326    TransactionMap::iterator j = mCandidateTransactionMap.find(tid);
00327    if(j != mCandidateTransactionMap.end())
00328    {
00329       cancelClientTransaction(j->second);
00330       mTerminatedTransactionMap[tid] = j->second;
00331       mCandidateTransactionMap.erase(j);
00332       return true;
00333    }
00334    
00335    return false;
00336 }
00337 
00338 Target* 
00339 ResponseContext::getTarget(const resip::Data& tid) const
00340 {
00341    // .bwc. This tid is most likely to be found in either the Candidate targets,
00342    // or the Active targets.
00343    TransactionMap::const_iterator pend = mCandidateTransactionMap.find(tid);
00344    if(pend != mCandidateTransactionMap.end())
00345    {
00346       assert(pend->second->status()==Target::Candidate);
00347       return pend->second;
00348    }
00349    
00350    TransactionMap::const_iterator act = mActiveTransactionMap.find(tid);
00351    if(act != mActiveTransactionMap.end())
00352    {
00353       assert(!(act->second->status()==Target::Candidate || act->second->status()==Target::Terminated));
00354       return act->second;
00355    }
00356 
00357    TransactionMap::const_iterator term = mTerminatedTransactionMap.find(tid);
00358    if(term != mTerminatedTransactionMap.end())
00359    {
00360       assert(term->second->status()==Target::Terminated);
00361       return term->second;
00362    }
00363 
00364    return 0;
00365 }
00366 
00367 const ResponseContext::TransactionMap& 
00368 ResponseContext::getCandidateTransactionMap() const
00369 {
00370    return mCandidateTransactionMap;
00371 }
00372 
00373 bool 
00374 ResponseContext::hasCandidateTransactions() const
00375 {
00376    return !mRequestContext.mHaveSentFinalResponse && !mCandidateTransactionMap.empty();
00377 }
00378 
00379 bool 
00380 ResponseContext::hasActiveTransactions() const
00381 {
00382    return !mActiveTransactionMap.empty();
00383 }
00384 
00385 bool 
00386 ResponseContext::hasTerminatedTransactions() const
00387 {
00388    return !mTerminatedTransactionMap.empty();
00389 }
00390 
00391 bool
00392 ResponseContext::hasTargets() const
00393 {
00394    return (hasCandidateTransactions() ||
00395             hasActiveTransactions() ||
00396             hasTerminatedTransactions());
00397 }
00398 
00399 bool 
00400 ResponseContext::areAllTransactionsTerminated() const
00401 {
00402    return (mCandidateTransactionMap.empty() && mActiveTransactionMap.empty());
00403 }
00404 
00405 bool
00406 ResponseContext::isCandidate(const resip::Data& tid) const
00407 {
00408    TransactionMap::const_iterator i=mCandidateTransactionMap.find(tid);
00409    return i!=mCandidateTransactionMap.end();
00410 }
00411 
00412 bool
00413 ResponseContext::isActive(const resip::Data& tid) const
00414 {
00415    TransactionMap::const_iterator i=mActiveTransactionMap.find(tid);
00416    return i!=mActiveTransactionMap.end();
00417 }
00418 
00419 bool
00420 ResponseContext::isTerminated(const resip::Data& tid) const
00421 {
00422    TransactionMap::const_iterator i=mTerminatedTransactionMap.find(tid);
00423    return i!=mTerminatedTransactionMap.end();
00424 }
00425 
00426 void 
00427 ResponseContext::removeClientTransaction(const resip::Data& transactionId)
00428 {
00429    // .bwc. This tid will most likely be found in the map of terminated
00430    // transactions, under normal circumstances.
00431    // NOTE: This does not remove the corresponding entry in mTargetList.
00432    // This is the intended behavior, because the same target should not
00433    // be added again later.
00434 
00435    TransactionMap::iterator i = mTerminatedTransactionMap.find(transactionId);
00436    if(i!=mTerminatedTransactionMap.end())
00437    {
00438       delete i->second;
00439       mTerminatedTransactionMap.erase(i);
00440       return;
00441    }
00442 
00443    i=mCandidateTransactionMap.find(transactionId);
00444    if(i!=mCandidateTransactionMap.end())
00445    {
00446       delete i->second;
00447       mCandidateTransactionMap.erase(i);
00448       return;
00449    }
00450    
00451    i=mActiveTransactionMap.find(transactionId);
00452    if(i!=mActiveTransactionMap.end())
00453    {
00454       delete i->second;
00455       mActiveTransactionMap.erase(i);
00456       WarningLog(<< "Something removed an active transaction, " << transactionId
00457                << ". It is very likely that something is broken here. ");
00458       return;
00459    }
00460          
00461 }
00462 
00463 bool
00464 ResponseContext::isDuplicate(const repro::Target* target) const
00465 {
00466    resip::ContactList::const_iterator i;
00467    // make sure each target is only inserted once
00468 
00469    // !bwc! We can not optimize this by using stl, because operator
00470    // == does not conform to the partial-ordering established by operator
00471    // <  (We can very easily have a < b and a==b simultaneously).
00472    // [TODO] Once we have a canonicalized form, we can improve this.
00473 
00474    for(i=mTargetList.begin();i!=mTargetList.end();i++)
00475    {
00476       if(*i==target->rec())
00477       {
00478          return true;
00479       }
00480    }
00481 
00482    return false;
00483 }
00484 
00485 void
00486 ResponseContext::beginClientTransaction(repro::Target* target)
00487 {
00488    // .bwc. This is a private function, and if anything calls this with a
00489    // target in an invalid state, it is a bug.
00490    assert(target->status() == Target::Candidate);
00491 
00492    SipMessage& orig=mRequestContext.getOriginalRequest();
00493    SipMessage request(orig);
00494 
00495    // If the target has a ;lr parameter, then perform loose routing
00496    if(target->uri().exists(p_lr))
00497    {
00498       request.header(h_Routes).push_front(NameAddr(target->uri()));
00499    }
00500    else
00501    {
00502       request.header(h_RequestLine).uri() = target->uri();
00503    }
00504 
00505    // .bwc. Proxy checks whether this is valid, and rejects if not.
00506    request.header(h_MaxForwards).value()--;
00507    
00508    bool inDialog=false;
00509    
00510    try
00511    {
00512       inDialog=request.header(h_To).exists(p_tag);
00513    }
00514    catch(resip::ParseException&)
00515    {
00516       // ?bwc? Do we ignore this and just say this is a dialog-creating
00517       // request?
00518    }
00519    
00520    // Potential source Record-Route addition only for new dialogs
00521    // !bwc! It looks like we really ought to be record-routing in-dialog
00522    // stuff.
00523 
00524    // only add record route if configured to do so
00525    if(!mRequestContext.mProxy.getRecordRoute(orig.getReceivedTransport()).uri().host().empty())
00526    {
00527       if (!inDialog &&  // only for dialog-creating request
00528           (request.method() == INVITE ||
00529            request.method() == SUBSCRIBE ||
00530            request.method() == REFER))
00531       {
00532          insertRecordRoute(request,
00533                            orig.getReceivedTransport(),
00534                            target);
00535       }
00536       else if(request.method()==REGISTER)
00537       {
00538          insertRecordRoute(request,
00539                            orig.getReceivedTransport(),
00540                            target,
00541                            true /* do Path instead */);
00542       }
00543    }
00544       
00545    if((resip::InteropHelper::getOutboundSupported() ||
00546        resip::InteropHelper::getRRTokenHackEnabled() ||
00547        mIsClientBehindNAT) &&
00548       target->rec().mUseFlowRouting &&
00549       target->rec().mReceivedFrom.mFlowKey)
00550    {
00551       // .bwc. We only override the destination if we are sending to an
00552       // outbound contact. If this is not an outbound contact, but the
00553       // endpoint has given us a Contact with the correct ip-address and 
00554       // port, we might be able to find the connection they formed when they
00555       // registered earlier, but that will happen down in TransportSelector.
00556       request.setDestination(target->rec().mReceivedFrom);
00557    }
00558 
00559    DebugLog(<<"Set tuple dest: " << request.getDestination());
00560 
00561    // .bwc. Path header addition.
00562    if(!target->rec().mSipPath.empty())
00563    {
00564       request.header(h_Routes).append(target->rec().mSipPath);
00565    }
00566 
00567    // a baboon might adorn the message, record call logs or CDRs, might
00568    // insert loose routes on the way to the next hop
00569    Helper::processStrictRoute(request);
00570    
00571    //This is where the request acquires the tid of the Target. The tids 
00572    //should be the same from here on out.
00573    request.header(h_Vias).push_front(target->via());
00574 
00575    if(!mRequestContext.mInitialTimerCSet &&
00576       mRequestContext.getOriginalRequest().method()==INVITE)
00577    {
00578       mRequestContext.mInitialTimerCSet=true;
00579       mRequestContext.updateTimerC();
00580    }
00581    
00582    // the rest of 16.6 is implemented by the transaction layer of resip
00583    // - determining the next hop (tuple)
00584    // - adding a content-length if needed
00585    // - sending the request
00586    sendRequest(request); 
00587 
00588    target->status() = Target::Started;
00589 }
00590 
00591 void
00592 ResponseContext::insertRecordRoute(SipMessage& outgoing,
00593                                    const Transport* receivedTransport,
00594                                    Target* target,
00595                                    bool doPathInstead)
00596 {
00597    resip::Data inboundFlowToken=getInboundFlowToken(doPathInstead);
00598    bool needsOutboundFlowToken=outboundFlowTokenNeeded(target);
00599    bool recordRouted=false;
00600    // .bwc. If we have a flow-token we need to insert, we need to record-route.
00601    // Also, we might record-route if we are configured to do so.
00602    if( !inboundFlowToken.empty() 
00603       || needsOutboundFlowToken 
00604       || mRequestContext.mProxy.getRecordRouteForced() )
00605    {
00606       resip::NameAddr rt;
00607       if(inboundFlowToken.empty())
00608       {
00609          rt=mRequestContext.mProxy.getRecordRoute(receivedTransport);
00610       }
00611       else
00612       {
00613          if(receivedTransport->getTuple().getType()==TLS || 
00614             receivedTransport->getTuple().getType()==DTLS)
00615          {
00616             // .bwc. Debatable. Should we be willing to reuse a TLS connection
00617             // at the behest of a Route header with no hostname in it?
00618             rt=mRequestContext.mProxy.getRecordRoute(receivedTransport);
00619             rt.uri().scheme() = "sips";
00620          }
00621          else
00622          {
00623             if(receivedTransport->getTuple().isAnyInterface())
00624             {
00625                rt=mRequestContext.mProxy.getRecordRoute(receivedTransport);
00626             }
00627             else
00628             {
00629                rt.uri().host()=resip::Tuple::inet_ntop(receivedTransport->getTuple());
00630             }
00631             rt.uri().port()=receivedTransport->getTuple().getPort();
00632             rt.uri().param(resip::p_transport)=resip::Tuple::toDataLower(receivedTransport->getTuple().getType());
00633          }
00634          rt.uri().user()=inboundFlowToken;
00635       }
00636       Helper::massageRoute(outgoing,rt);
00637 
00638 #ifdef USE_SIGCOMP
00639       if(mRequestContext.getProxy().compressionEnabled() &&
00640          target->uri().exists(p_comp) &&
00641          target->uri().param(p_comp)=="sigcomp")
00642       {
00643          rt.uri().param(p_comp)="sigcomp";
00644       }
00645 #endif
00646 
00647       recordRouted=true;
00648       if(doPathInstead)
00649       {
00650          if(!inboundFlowToken.empty())
00651          {
00652             // Only add ;ob parameter if client really supports outbound (ie. not for NAT detection mode or flow token hack)
00653             if(!mRequestContext.getOriginalRequest().empty(h_Supporteds) &&
00654                mRequestContext.getOriginalRequest().header(h_Supporteds).find(Token(Symbols::Outbound)))
00655             {
00656                rt.uri().param(p_ob);
00657             }
00658          }
00659          outgoing.header(h_Paths).push_front(rt);
00660          if(!outgoing.header(h_Supporteds).find(Token("path")))
00661          {
00662             outgoing.header(h_Supporteds).push_back(Token("path"));
00663          }
00664          InfoLog (<< "Added Path: " << rt);
00665       }
00666       else
00667       {
00668          outgoing.header(h_RecordRoutes).push_front(rt);
00669          InfoLog (<< "Added Record-Route: " << rt);
00670       }
00671    }
00672 
00673    // .bwc. We always need to add this, since we never know if a transport 
00674    // switch is going to happen. (Except for Path headers; we don't care about 
00675    // transport switches on REGISTER requests. If we already put a Path header 
00676    // in, we do care though.)
00677    if(!doPathInstead || recordRouted)
00678    {
00679       std::auto_ptr<resip::MessageDecorator> rrDecorator(
00680                                  new RRDecorator(mRequestContext.mProxy,
00681                                                 receivedTransport,
00682                                                 recordRouted,
00683                                                 !inboundFlowToken.empty(),
00684                                                 mRequestContext.mProxy.getRecordRouteForced(),
00685                                                 doPathInstead,
00686                                                 mIsClientBehindNAT));
00687       outgoing.addOutboundDecorator(rrDecorator);
00688    }
00689 }
00690 
00691 resip::Data
00692 ResponseContext::getInboundFlowToken(bool doPathInstead)
00693 {
00694    resip::Data flowToken=resip::Data::Empty;
00695    resip::SipMessage& orig=mRequestContext.getOriginalRequest();
00696    if(orig.empty(h_Contacts) || !orig.header(h_Contacts).front().isWellFormed())
00697    {
00698       return flowToken;
00699    }
00700 
00701    const resip::NameAddr& contact(orig.header(h_Contacts).front());
00702 
00703    if(InteropHelper::getOutboundSupported() && 
00704       (contact.uri().exists(p_ob) || contact.exists(p_regid)))
00705    {
00706       if(orig.header(h_Vias).size()==1)
00707       {
00708          // This arrived over an outbound flow (or so the endpoint claims)
00709          // (See outbound-09 Sec 4.3 para 3)
00710          resip::Data binaryFlowToken;
00711          resip::Tuple source(orig.getSource());
00712          source.onlyUseExistingConnection=true;
00713          Tuple::writeBinaryToken(source, binaryFlowToken, Proxy::FlowTokenSalt);
00714          flowToken = binaryFlowToken.base64encode();
00715       }
00716       else if(doPathInstead)
00717       {
00718          // Need to try to detect Path failures
00719          if(orig.empty(h_Paths) || !orig.header(h_Paths).back().uri().exists(p_ob))
00720          {
00721             // Yikes! Client is trying to use outbound, but edge-proxy did not
00722             // support it. The registrar will either reject this (if it supports 
00723             // outbound), or will not indicate outbound support (which should 
00724             // let the client know that the flow setup failed)
00725             WarningLog(<<"Client asked for outbound processing, but the edge "
00726                      "proxy did not support it. There's nothing we can do to "
00727                      "salvage this. The registrar might end up rejecting the "
00728                      "registration (if is supports outbound), or it might just "
00729                      "fail to add a Supported: outbound. In either case, the "
00730                      "client should know what's up, so we just let it all "
00731                      "happen.");
00732          }
00733       }
00734    }
00735 
00736    if(flowToken.empty() && orig.header(h_Vias).size()==1)
00737    {
00738       if(resip::InteropHelper::getRRTokenHackEnabled() ||
00739          mIsClientBehindNAT ||
00740          needsFlowTokenToWork(contact))
00741       {
00742          // !bwc! TODO remove this when flow-token hack is no longer needed.
00743          // Poor-man's outbound. Shouldn't be our default behavior, because it
00744          // breaks target-refreshes (once a flow-token is in the Route-Set, the 
00745          // flow-token cannot be changed, and will override any update to the 
00746          // Contact)
00747          resip::Data binaryFlowToken;
00748          Tuple::writeBinaryToken(orig.getSource(), binaryFlowToken, Proxy::FlowTokenSalt);
00749          flowToken = binaryFlowToken.base64encode();
00750       }
00751    }
00752 
00753    return flowToken;
00754 }
00755 
00756 bool
00757 ResponseContext::outboundFlowTokenNeeded(Target* target)
00758 {
00759    if(mRequestContext.mProxy.isMyUri(target->uri()))
00760    {
00761       // .bwc. We don't need to put flow-tokens pointed at ourselves.
00762       return false;
00763    }
00764 
00765    if((target->rec().mReceivedFrom.mFlowKey &&
00766        target->rec().mUseFlowRouting)
00767       || resip::InteropHelper::getRRTokenHackEnabled()
00768       || mIsClientBehindNAT)
00769    {
00770       target->rec().mReceivedFrom.onlyUseExistingConnection=true;
00771       return true;
00772    }
00773 
00774    return false;
00775 }
00776 
00777 bool 
00778 ResponseContext::needsFlowTokenToWork(const resip::NameAddr& contact) const
00779 {
00780    if(DnsUtil::isIpAddress(contact.uri().host()))
00781    {
00782       // IP address in host-part.
00783       if(contact.uri().scheme()=="sips")
00784       {
00785          // TLS with no FQDN. Impossible without flow-token fixup, even if no 
00786          // NAT is involved.
00787          return true;
00788       }
00789 
00790       if(contact.uri().exists(p_transport))
00791       {
00792          TransportType type = toTransportType(contact.uri().param(p_transport));
00793          if(type==TLS || type == DTLS)
00794          {
00795             // TLS with no FQDN. Impossible without flow-token fixup, even if no 
00796             // NAT is involved.
00797             return true;
00798          }
00799       }
00800    }
00801 
00802    if(contact.uri().exists(p_sigcompId))
00803    {
00804       if(contact.uri().exists(p_transport))
00805       {
00806          TransportType type = toTransportType(contact.uri().param(p_transport));
00807          if(type == TLS || type == TCP)
00808          {
00809             // Client is using sigcomp on the first hop using a connection-
00810             // oriented transport. For this to work, that connection has to be
00811             // reused for all traffic.
00812             return true;
00813          }
00814       }
00815    }
00816    return false;
00817 }
00818 
00819 bool
00820 ResponseContext::sendingToSelf(Target* target)
00821 {
00822    if(mRequestContext.mProxy.isMyUri(target->uri()))
00823    {
00824       return true;
00825    }
00826    return false;
00827 }
00828 
00829 void 
00830 ResponseContext::sendRequest(resip::SipMessage& request)
00831 {
00832    assert (request.isRequest());
00833 
00834    if (request.method() != CANCEL && 
00835        request.method() != ACK)
00836    {
00837       mRequestContext.getProxy().addClientTransaction(request.getTransactionId(), &mRequestContext);
00838       mRequestContext.mTransactionCount++;
00839 //      if(!mRequestContext.getDigestIdentity().empty())
00840 //      {
00841 //         requestPtr->header(h_Identity);
00842 //         // !bwc! Need to fill in the Identity-Info header telling where our 
00843 //         // cert can be found.
00844 //      }
00845    }
00846 
00847    // TODO - P-Asserted-Identity Processing
00848    // RFC3325 - section 5
00849    // When a proxy forwards a message to another node, it must first
00850    // determine if it trusts that node or not.  If it trusts the node, the
00851    // proxy does not remove any P-Asserted-Identity header fields that it
00852    // generated itself, or that it received from a trusted source.  If it
00853    // does not trust the element, then the proxy MUST examine the Privacy
00854    // header field (if present) to determine if the user requested that
00855    // asserted identity information be kept private.
00856 
00857    // Note:  Since we have no better mechanism to determine if destination is trusted or
00858    //        not we will assume that all destinations outside our domain are not-trusted
00859    //        and will remove the P-Asserted-Identity header, if Privacy is set to "id"
00860    if(mRequestContext.getProxy().isPAssertedIdentityProcessingEnabled() &&
00861       request.exists(h_Privacies) && 
00862       request.header(h_Privacies).size() > 0 && 
00863       request.exists(h_PAssertedIdentities) && 
00864       !mRequestContext.getProxy().isMyUri(request.header(h_RequestLine).uri()))
00865    {
00866       // Look for "id" token
00867       bool found = false;
00868       PrivacyCategories::iterator it = request.header(h_Privacies).begin();
00869       for(; it != request.header(h_Privacies).end() && !found; it++)
00870       {
00871          std::vector<Data>::iterator itToken = it->value().begin();
00872          for(; itToken != it->value().end() && !found; itToken++)
00873          {
00874             if(*itToken == "id")
00875             {
00876                request.remove(h_PAssertedIdentities); 
00877                found = true;
00878             }
00879          }
00880       }
00881    }
00882 
00883    if (request.method() == ACK)
00884    {
00885      DebugLog(<<"Posting Ack200DoneMessage");
00886      mRequestContext.getProxy().post(new Ack200DoneMessage(mRequestContext.getTransactionId()));
00887    }
00888 
00889    mRequestContext.send(request);
00890 }
00891 
00892 
00893 void
00894 ResponseContext::processCancel(const SipMessage& request)
00895 {
00896    assert(request.isRequest());
00897    assert(request.method() == CANCEL);
00898 
00899    std::auto_ptr<SipMessage> ok(Helper::makeResponse(request, 200));   
00900    mRequestContext.sendResponse(*ok);
00901 
00902    if (!mRequestContext.mHaveSentFinalResponse)
00903    {
00904       cancelAllClientTransactions();
00905       if(!hasActiveTransactions())
00906       {
00907          SipMessage reqterm;
00908          Helper::makeResponse(reqterm,mRequestContext.getOriginalRequest(),487);
00909          mRequestContext.sendResponse(reqterm);
00910       }
00911    }
00912 }
00913 
00914 void
00915 ResponseContext::processTimerC()
00916 {
00917    if (!mRequestContext.mHaveSentFinalResponse)
00918    {
00919       InfoLog(<<"Canceling client transactions due to timer C.");
00920       cancelAllClientTransactions();
00921    }
00922 }
00923 
00924 void
00925 ResponseContext::processResponse(SipMessage& response)
00926 {
00927    InfoLog (<< "processResponse: " << endl << response);
00928 
00929    // store this before we pop the via and lose the branch tag
00930    mCurrentResponseTid = response.getTransactionId();
00931    
00932    assert (response.isResponse());
00933    assert (response.exists(h_Vias) && !response.header(h_Vias).empty());
00934    response.header(h_Vias).pop_front();
00935 
00936    // Stop processing responses that have nowhere else to go
00937    if (response.header(h_Vias).empty())
00938    {
00939       // CANCEL/200s only have one Via.  Likewise 100s only have one Via  
00940       // Silently stop processing the CANCEL responses.
00941       // We will handle the 100 responses later
00942       // Log other responses we can't forward
00943 
00944       if(response.method()==CANCEL)
00945       {
00946          return;
00947       }
00948       else if (response.header(h_StatusLine).statusCode() > 199)
00949       {
00950          InfoLog( << "Received final response, but can't forward as there are "
00951                         "no more Vias. Considering this branch failed. " 
00952                         << response.brief() );
00953          // .bwc. Treat as server error.
00954          terminateClientTransaction(mCurrentResponseTid);
00955          return;
00956       }
00957       else if(response.header(h_StatusLine).statusCode() != 100)
00958       {
00959          InfoLog( << "Received provisional response, but can't forward as there"
00960                      " are no more Vias. Ignoring. " << response.brief() );
00961          return;
00962       }
00963    }
00964    else // We have a second Via
00965    {
00966       if(!mRequestContext.getOriginalRequest().getRFC2543TransactionId().empty())
00967       {
00968          // .bwc. Original request had an RFC 2543 transaction-id. Set in 
00969          // response.
00970          response.setRFC2543TransactionId(mRequestContext.getOriginalRequest().getRFC2543TransactionId());
00971       }
00972 
00973       const Via& via = response.header(h_Vias).front();
00974 
00975       if(!via.isWellFormed())
00976       {
00977          // .bwc. Garbage via. Unrecoverable. Ignore if provisional, terminate
00978          // transaction if not.
00979          DebugLog(<<"Some endpoint has corrupted one of our Vias"
00980             " in their response. (Via is malformed) This is not fixable.");
00981          if(response.header(h_StatusLine).statusCode() > 199)
00982          {
00983             terminateClientTransaction(mCurrentResponseTid);
00984          }
00985          
00986          return;
00987       }
00988 
00989       const Via& origVia = mRequestContext.getOriginalRequest().header(h_Vias).front();
00990       const Data& branch=(via.exists(p_branch) ? via.param(p_branch).getTransactionId() : Data::Empty);
00991       const Data& origBranch=(origVia.exists(p_branch) ? origVia.param(p_branch).getTransactionId() : Data::Empty);
00992 
00993       if(!isEqualNoCase(branch,origBranch))
00994       {
00995          // .bwc. Someone altered our branch. Ignore if provisional, terminate 
00996          // transaction otherwise.
00997          DebugLog(<<"Some endpoint has altered one of our Vias"
00998             " in their response. (branch is different) This is not fixable.");
00999          if(response.header(h_StatusLine).statusCode() > 199)
01000          {
01001             terminateClientTransaction(mCurrentResponseTid);
01002          }
01003          
01004          return;
01005       }
01006    }
01007    
01008    DebugLog (<< "Search for " << mCurrentResponseTid << " in " << InserterP(mActiveTransactionMap));
01009 
01010    TransactionMap::iterator i = mActiveTransactionMap.find(mCurrentResponseTid);
01011 
01012    int code = response.header(h_StatusLine).statusCode();
01013    if (i == mActiveTransactionMap.end())
01014    {
01015       // This is a response for a transaction that is no longer/was never active.  
01016       // This is probably a useless response (at best) or a malicious response (at worst).
01017       // Log the response here:
01018       if ((code / 100) != 2)
01019       {
01020          InfoLog( << "Discarding stray response" );
01021       }
01022       // Even though this is a tremendously bad idea, some developers may
01023       // decide they want to statelessly forward the response
01024       // Here is the gun.  Don't say we didn't warn you!
01025       else
01026       {
01027          // !abr! Because we don't run timers on the transaction after
01028          //       it has terminated and because the ACKs on INVITE
01029          //       200-class responses are end-to-end, we don't discard
01030          //       200 responses. To do this properly, we should run a
01031          //       transaction timer for 64*T1 and remove transactions from
01032          //       the ActiveTransactionMap *only* after that timer expires.
01033          //       IN OTHER WORDS, REMOVE THIS CODE.
01034          mRequestContext.sendResponse(response);
01035       }
01036       return;
01037    }
01038 
01039    switch (code / 100)
01040    {
01041       case 1:
01042          if(mRequestContext.getOriginalRequest().method()==INVITE)
01043          {
01044             mRequestContext.updateTimerC();
01045          }
01046 
01047          if  (!mRequestContext.mHaveSentFinalResponse)
01048          {
01049             if (code == 100)
01050             {
01051                return;  // stop processing 100 responses
01052             }
01053                
01054             mRequestContext.sendResponse(response);
01055             return;            
01056          }
01057          break;
01058          
01059       case 2:
01060          terminateClientTransaction(mCurrentResponseTid);
01061          if (mRequestContext.getOriginalRequest().method() == INVITE)
01062          {
01063             cancelAllClientTransactions();
01064             mRequestContext.mHaveSentFinalResponse = true;
01065             mBestResponse.header(h_StatusLine).statusCode()=
01066                response.header(h_StatusLine).statusCode();
01067             mRequestContext.sendResponse(response);
01068          }
01069          else if (!mRequestContext.mHaveSentFinalResponse)
01070          {
01071             clearCandidateTransactions();
01072             mRequestContext.mHaveSentFinalResponse = true;
01073             mBestResponse.header(h_StatusLine).statusCode()=
01074                response.header(h_StatusLine).statusCode();
01075 
01076             // If this is a registration response and we have flow timers enabled, and
01077             // we are doing outbound for this registration and there is no FlowTimer
01078             // header present already, then add a FlowTimer header
01079             if(response.method() == REGISTER &&
01080                InteropHelper::getFlowTimerSeconds() > 0 &&
01081                response.empty(h_FlowTimer) &&
01082                ((!response.empty(h_Paths) && response.header(h_Paths).back().uri().exists(p_ob)) ||
01083                 (!response.empty(h_Requires) && response.header(h_Requires).find(Token(Symbols::Outbound)))))
01084             {
01085                response.header(h_FlowTimer).value() = InteropHelper::getFlowTimerSeconds();
01086                mRequestContext.getProxy().getStack().enableFlowTimer(mRequestContext.getOriginalRequest().getSource());
01087             }
01088 
01089             mRequestContext.sendResponse(response);            
01090          }
01091          break;
01092          
01093       case 3:
01094       case 4:
01095       case 5:
01096          DebugLog (<< "forwardedFinal=" << mRequestContext.mHaveSentFinalResponse 
01097                    << " outstanding client transactions: " << InserterP(mActiveTransactionMap));
01098          terminateClientTransaction(mCurrentResponseTid);
01099          if (!mRequestContext.mHaveSentFinalResponse)
01100          {
01101             int priority = getPriority(response);
01102             if (priority == mBestPriority)
01103             {
01104                if (code == 401 || code == 407)
01105                {
01106                   if (response.exists(h_WWWAuthenticates))
01107                   {
01108                      for ( Auths::iterator i=response.header(h_WWWAuthenticates).begin(); 
01109                            i != response.header(h_WWWAuthenticates).end() ; ++i)
01110                      {                     
01111                         mBestResponse.header(h_WWWAuthenticates).push_back(*i);
01112                      }
01113                   }
01114                   
01115                   if (response.exists(h_ProxyAuthenticates))
01116                   {
01117                      for ( Auths::iterator i=response.header(h_ProxyAuthenticates).begin(); 
01118                            i != response.header(h_ProxyAuthenticates).end() ; ++i)
01119                      {                     
01120                         mBestResponse.header(h_ProxyAuthenticates).push_back(*i);
01121                      }
01122                      mBestResponse.header(h_StatusLine).statusCode() = 407;
01123                   }
01124                }
01125                else if (code / 100 == 3) // merge 3xx
01126                {
01127 
01128                   if(mBestResponse.header(h_StatusLine).statusCode()/100!=3)
01129                   {
01130                      // .bwc. Do not merge contacts in 3xx with contacts from a
01131                      // previous 4xx or 5xx
01132                      mBestResponse.header(h_Contacts).clear();
01133                   }
01134 
01135                   for (NameAddrs::iterator i=response.header(h_Contacts).begin(); 
01136                        i != response.header(h_Contacts).end(); ++i)
01137                   {
01138                      // TODO ?bwc? if we are going to be checking whether
01139                      // this is "*", we should see if it is well-formed
01140                      // first. If we shouldn't be doing any checks on
01141                      // the contacts, we should simply remove all of this
01142                      // checking code and just blindly copy the contacts over.
01143 
01144                      if(!i->isWellFormed() || i->isAllContacts())
01145                      {
01146                         // .bwc. Garbage contact; ignore it.
01147                         continue;
01148                      }
01149                      
01150                      mBestResponse.header(h_Contacts).push_back(*i);
01151                   }
01152 
01153                   // ?bwc? it is possible for this code to end up with a 300
01154                   // with no Contacts in it (because they were all malformed)
01155                   // Is this acceptable? Also, is 300 the code we want here?
01156                   mBestResponse.header(h_StatusLine).statusCode() = 300;
01157                }
01158             }
01159             else if (priority < mBestPriority)
01160             {
01161                mBestPriority = priority;
01162                mBestResponse = response;
01163             }
01164             
01165             if (areAllTransactionsTerminated())
01166             {
01167                forwardBestResponse();
01168             }
01169          }
01170          break;
01171          
01172       case 6:
01173          terminateClientTransaction(mCurrentResponseTid);
01174          if (!mRequestContext.mHaveSentFinalResponse)
01175          {
01176             if (mBestResponse.header(h_StatusLine).statusCode() / 100 != 6)
01177             {
01178                mBestResponse = response;
01179                mBestPriority=0; //6xx class responses take precedence over all 3xx,4xx, and 5xx
01180                if (mRequestContext.getOriginalRequest().method() == INVITE)
01181                {
01182                   // CANCEL INVITE branches
01183                   cancelAllClientTransactions();
01184                }
01185             }
01186             
01187             if (areAllTransactionsTerminated())
01188             {
01189                forwardBestResponse();
01190             }
01191          }
01192          break;
01193          
01194       default:
01195          assert(0);
01196          break;
01197    }
01198 }
01199 
01200 void
01201 ResponseContext::cancelClientTransaction(repro::Target* target)
01202 {
01203    if (target->status() == Target::Started)
01204    {
01205       InfoLog (<< "Cancel client transaction: " << target);
01206       mRequestContext.cancelClientTransaction(target->via().param(p_branch).getTransactionId());
01207 
01208       DebugLog(<< "Canceling a transaction with uri: " 
01209                << resip::Data::from(target->uri()) << " , to host: " 
01210                << target->via().sentHost());
01211       target->status() = Target::Cancelled;
01212    }
01213    else if (target->status() == Target::Candidate)
01214    {
01215       target->status() = Target::Terminated;
01216    }
01217 }
01218 
01219 void 
01220 ResponseContext::terminateClientTransaction(const resip::Data& tid)
01221 {
01222 
01223    InfoLog (<< "Terminating client transaction: " << tid << " all = " << areAllTransactionsTerminated());
01224 
01225    TransactionMap::iterator i = mActiveTransactionMap.find(tid);
01226    if(i != mActiveTransactionMap.end())
01227    {
01228       InfoLog (<< "client transactions: " << InserterP(mActiveTransactionMap));
01229       i->second->status() = Target::Terminated;
01230       mTerminatedTransactionMap[tid] = i->second;
01231       mActiveTransactionMap.erase(i);
01232       return;
01233    }
01234    
01235    TransactionMap::iterator j = mCandidateTransactionMap.find(tid);
01236    if(j != mCandidateTransactionMap.end())
01237    {
01238       InfoLog (<< "client transactions: " << InserterP(mCandidateTransactionMap));
01239       j->second->status() = Target::Terminated;
01240       mTerminatedTransactionMap[tid] = j->second;
01241       mCandidateTransactionMap.erase(j);
01242       return;   
01243    }
01244       
01245 }
01246 
01247 
01248 int
01249 ResponseContext::getPriority(const resip::SipMessage& msg)
01250 {
01251    int responseCode = msg.header(h_StatusLine).statusCode();
01252    int p = 0;  // "p" is the relative priority of the response
01253 
01254       assert(responseCode >= 300 && responseCode <= 599);
01255       if (responseCode <= 399)  // 3xx response
01256       { 
01257          return 5;  // response priority is 5
01258       }
01259       if (responseCode >= 500)
01260       {
01261          switch(responseCode)
01262          {
01263             case 501:   // these four have different priorities
01264             case 503:   // which are addressed in the case statement
01265             case 580:   // below (with the 4xx responses)
01266             case 513:
01267                   break;
01268             default:
01269                   return 42; // response priority of other 5xx is 42
01270          }
01271       }
01272 
01273       switch(responseCode)
01274       {
01275          // Easy to Repair Responses: 412, 484, 422, 423, 407, 401, 300..399, 402
01276          case 412:              // Publish ETag was stale
01277             return 1;
01278          case 484:              // overlap dialing
01279             return 2;
01280          case 422:              // Session-Timer duration too long
01281          case 423:              // Expires too short
01282             return 3;
01283          case 407:              // Proxy-Auth
01284          case 401:              // UA Digest challenge
01285             return 4;
01286                   
01287          // 3xx responses have p = 5
01288          case 402:              // Payment required
01289             return 6;
01290 
01291          // Responses used for negotiation: 493, 429, 420, 406, 415, 488
01292          case 493:              // Undecipherable, try again unencrypted 
01293             return 10;
01294 
01295          case 420:              // Required Extension not supported, try again without
01296             return 12;
01297 
01298          case 406:              // Not Acceptable
01299          case 415:              // Unsupported Media Type
01300          case 488:              // Not Acceptable Here
01301             return 13;
01302                   
01303          // Possibly useful for negotiation, but less likely: 421, 416, 417, 494, 580, 485, 405, 501, 413, 414
01304          
01305          case 416:              // Unsupported scheme
01306          case 417:              // Unknown Resource-Priority
01307             return 20;
01308 
01309          case 405:              // Method not allowed (both used for negotiating REFER, PUBLISH, etc..
01310          case 501:              // Usually used when the method is not OK
01311             return 21;
01312 
01313          case 580:              // Preconditions failure
01314             return 22;
01315 
01316          case 485:              // Ambiguous userpart.  A bit better than 404?
01317             return 23;
01318 
01319          case 428:              // Use Identity header
01320          case 429:              // Provide Referrer Identity 
01321          case 494:              // Use the sec-agree mechanism
01322             return 24;
01323 
01324          case 413:              // Request too big
01325          case 414:              // URI too big
01326             return 25;
01327 
01328          case 421:              // An extension required by the server was not in the Supported header
01329             return 26;
01330          
01331          // The request isn't repairable, but at least we can try to provide some 
01332          // useful information: 486, 480, 410, 404, 403, 487
01333          
01334          case 486:              // Busy Here
01335             return 30;
01336 
01337          case 480:              // Temporarily unavailable
01338             return 31;
01339 
01340          case 410:              // Gone
01341             return 32;
01342 
01343          case 436:              // Bad Identity-Info 
01344          case 437:              // Unsupported Certificate
01345          case 513:      // Message too large
01346             return 33;
01347 
01348          case 403:              // Forbidden
01349             return 34;
01350 
01351          case 404:              // Not Found
01352             return 35;
01353 
01354          case 487:              // Some branches were cancelled, if the UAC sent a CANCEL this is good news
01355             return 36;
01356 
01357          // We are hosed: 503, 483, 482, 481, other 5xx, 400, 491, 408  // totally useless
01358 
01359          case 503:      // bad news, we should never forward this back anyway
01360             return 43;
01361 
01362          case 483:      // loops, encountered
01363          case 482:
01364             return 41;
01365                   
01366          // other 5xx   p = 42
01367 
01368          // UAS is seriously confused: p = 43
01369          // case 481:   
01370          // case 400:
01371          // case 491:
01372          // default:
01373          
01374          case 408:      // very, very bad  (even worse than the remaining 4xx responses)
01375             return 49;
01376          
01377          default:
01378             return 43;
01379       }
01380    return p;
01381 }
01382 
01383 bool 
01384 ResponseContext::CompareStatus::operator()(const resip::SipMessage& lhs, const resip::SipMessage& rhs) const
01385 {
01386    assert(lhs.isResponse());
01387    assert(rhs.isResponse());
01388    
01389    // !rwm! replace with correct thingy here
01390    return lhs.header(h_StatusLine).statusCode() < rhs.header(h_StatusLine).statusCode();
01391 }
01392 
01393 void
01394 ResponseContext::forwardBestResponse()
01395 {
01396    InfoLog (<< "Forwarding best response: " << mBestResponse.brief());
01397    
01398    clearCandidateTransactions();
01399    
01400    if(mRequestContext.getOriginalRequest().method()==INVITE)
01401    {
01402       cancelActiveClientTransactions();
01403    }
01404    
01405    if(mBestResponse.header(h_StatusLine).statusCode() == 503)
01406    {
01407       //See RFC 3261 sec 16.7, page 110, paragraph 2
01408       mBestResponse.header(h_StatusLine).statusCode() = 480;
01409    }
01410 
01411    if(mBestResponse.header(h_StatusLine).statusCode() == 408 &&
01412       mBestResponse.method()!=INVITE)
01413    {
01414       // We don't forward back NIT 408; we just silently abandon the transaction - RFC4321 - section 1.4 408 for non-INVITE is not useful
01415       DebugLog(<< "Got NIT 408, abandoning: "<<mRequestContext.getTransactionId());
01416       mRequestContext.getProxy().getStack().abandonServerTransaction(mRequestContext.getTransactionId());
01417       mRequestContext.mHaveSentFinalResponse = true;  // To avoid Request context from sending a response
01418    }
01419    else
01420    {
01421       mRequestContext.sendResponse(mBestResponse);
01422    }
01423 }
01424 
01425 EncodeStream&
01426 repro::operator<<(EncodeStream& strm, const ResponseContext& rc)
01427 {
01428    strm << "ResponseContext: "
01429         << " identity=" << rc.mRequestContext.getDigestIdentity()
01430         << " best=" << rc.mBestPriority << " " << rc.mBestResponse.brief()
01431         << " forwarded=" << rc.mRequestContext.mHaveSentFinalResponse
01432         << " pending=" << InserterP(rc.mCandidateTransactionMap)
01433         << " active=" << InserterP(rc.mActiveTransactionMap)
01434         << " terminated=" << InserterP(rc.mTerminatedTransactionMap);
01435 
01436    return strm;
01437 }
01438 
01439 
01440 /* ====================================================================
01441  * The Vovida Software License, Version 1.0 
01442  * 
01443  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
01444  * 
01445  * Redistribution and use in source and binary forms, with or without
01446  * modification, are permitted provided that the following conditions
01447  * are met:
01448  * 
01449  * 1. Redistributions of source code must retain the above copyright
01450  *    notice, this list of conditions and the following disclaimer.
01451  * 
01452  * 2. Redistributions in binary form must reproduce the above copyright
01453  *    notice, this list of conditions and the following disclaimer in
01454  *    the documentation and/or other materials provided with the
01455  *    distribution.
01456  * 
01457  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
01458  *    and "Vovida Open Communication Application Library (VOCAL)" must
01459  *    not be used to endorse or promote products derived from this
01460  *    software without prior written permission. For written
01461  *    permission, please contact vocal@vovida.org.
01462  *
01463  * 4. Products derived from this software may not be called "VOCAL", nor
01464  *    may "VOCAL" appear in their name, without prior written
01465  *    permission of Vovida Networks, Inc.
01466  * 
01467  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
01468  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
01469  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
01470  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
01471  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
01472  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
01473  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
01474  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
01475  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
01476  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
01477  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
01478  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
01479  * DAMAGE.
01480  * 
01481  * ====================================================================
01482  * 
01483  * This software consists of voluntary contributions made by Vovida
01484  * Networks, Inc. and many individuals on behalf of Vovida Networks,
01485  * Inc.  For more information on Vovida Networks, Inc., please see
01486  * <http://www.vovida.org/>.
01487  *
01488  */