1
#if defined(HAVE_CONFIG_H)
7
#include "resip/stack/ExtensionParameter.hxx"
8
#include "resip/stack/InteropHelper.hxx"
9
#include "resip/stack/SipMessage.hxx"
10
#include "resip/stack/SipStack.hxx"
11
#include "rutil/DnsUtil.hxx"
12
#include "rutil/Inserter.hxx"
13
#include "resip/stack/Helper.hxx"
14
#include "rutil/Logger.hxx"
15
#include "repro/Proxy.hxx"
16
#include "repro/ResponseContext.hxx"
17
#include "repro/RequestContext.hxx"
18
#include "repro/RRDecorator.hxx"
19
#include "repro/Ack200DoneMessage.hxx"
20
#include "rutil/WinLeakCheck.hxx"
22
#define RESIPROCATE_SUBSYSTEM resip::Subsystem::REPRO
24
using namespace resip;
25
using namespace repro;
28
ResponseContext::ResponseContext(RequestContext& context) :
29
mRequestContext(context),
31
mSecure(false), //context.getOriginalRequest().header(h_RequestLine).uri().scheme() == Symbols::Sips)
32
mIsClientBehindNAT(false)
37
ResponseContext::~ResponseContext()
39
TransactionMap::iterator i;
41
for(i=mTerminatedTransactionMap.begin(); i!=mTerminatedTransactionMap.end();++i)
45
mTerminatedTransactionMap.clear();
47
for(i=mActiveTransactionMap.begin(); i!=mActiveTransactionMap.end();++i)
51
mActiveTransactionMap.clear();
53
for(i=mCandidateTransactionMap.begin(); i!=mCandidateTransactionMap.end();++i)
57
mCandidateTransactionMap.clear();
61
ResponseContext::addTarget(const NameAddr& addr, bool beginImmediately)
63
InfoLog (<< "Adding candidate " << addr);
64
std::auto_ptr<Target> target(new Target(addr));
65
Data tid=target->tid();
66
addTarget(target, beginImmediately);
71
ResponseContext::addTarget(std::auto_ptr<repro::Target> target, bool beginImmediately)
73
if(mRequestContext.mHaveSentFinalResponse || !target.get())
78
//Disallow sip: if secure
79
if(mSecure && target->uri().scheme() != Symbols::Sips)
84
//Make sure we don't have Targets with an invalid initial state.
85
if(target->status() != Target::Candidate)
92
if(isDuplicate(target.get()))
97
mTargetList.push_back(target->rec());
99
beginClientTransaction(target.get());
100
target->status()=Target::Started;
101
Target* toAdd=target.release();
102
mActiveTransactionMap[toAdd->tid()]=toAdd;
106
if(target->mShouldAutoProcess) // note: for base repro - this is always true
108
std::list<resip::Data> queue;
109
queue.push_back(target->tid());
110
mTransactionQueueCollection.push_back(queue);
113
Target* toAdd=target.release();
114
mCandidateTransactionMap[toAdd->tid()]=toAdd;
121
ResponseContext::addTargetBatch(TargetPtrList& targets,
124
std::list<resip::Data> queue;
126
TargetPtrList::iterator it;
128
if(mRequestContext.mHaveSentFinalResponse || targets.empty())
130
for(it=targets.begin();it!=targets.end();it++)
139
for(it=targets.begin();it!=targets.end();it++)
143
if((!mSecure || target->uri().scheme() == Symbols::Sips) &&
144
target->status() == Target::Candidate)
146
if(target->mShouldAutoProcess)
148
queue.push_back(target->tid());
150
DebugLog(<<"Adding Target to Candidates: " << target->uri() << " tid=" << target->tid());
151
mCandidateTransactionMap[target->tid()]=target;
155
DebugLog(<<"Bad Target: " << target->uri());
162
if(highPriority) // note: for base repro - this is always false
164
mTransactionQueueCollection.push_front(queue);
168
mTransactionQueueCollection.push_back(queue);
175
ResponseContext::beginClientTransactions()
179
if(mCandidateTransactionMap.empty())
184
for (TransactionMap::iterator i=mCandidateTransactionMap.begin(); i != mCandidateTransactionMap.end(); )
186
if(!isDuplicate(i->second) && !mRequestContext.mHaveSentFinalResponse)
188
mTargetList.push_back(i->second->rec()); // Add to Target list for future duplicate detection
189
beginClientTransaction(i->second);
191
// see rfc 3261 section 16.6
192
//This code moves the Target from mCandidateTransactionMap to mActiveTransactionMap,
193
//and begins the transaction.
194
mActiveTransactionMap[i->second->tid()] = i->second;
195
InfoLog (<< "Creating new client transaction " << i->second->tid() << " -> " << i->second->uri());
199
i->second->status() = Target::Terminated;
200
mTerminatedTransactionMap[i->second->tid()] = i->second;
201
DebugLog(<<"Found a repeated target.");
204
TransactionMap::iterator temp=i;
206
mCandidateTransactionMap.erase(temp);
213
ResponseContext::beginClientTransaction(const resip::Data& tid)
215
TransactionMap::iterator i = mCandidateTransactionMap.find(tid);
216
if(i==mCandidateTransactionMap.end())
221
if(isDuplicate(i->second) || mRequestContext.mHaveSentFinalResponse)
223
i->second->status() = Target::Terminated;
224
mTerminatedTransactionMap[i->second->tid()] = i->second;
225
mCandidateTransactionMap.erase(i);
229
mTargetList.push_back(i->second->rec()); // Add to Target list for future duplicate detection
231
beginClientTransaction(i->second);
232
mActiveTransactionMap[i->second->tid()] = i->second;
233
InfoLog(<< "Creating new client transaction " << i->second->tid() << " -> " << i->second->uri());
234
mCandidateTransactionMap.erase(i);
240
ResponseContext::cancelActiveClientTransactions()
242
if(mRequestContext.mHaveSentFinalResponse)
247
InfoLog (<< "Cancel all proceeding client transactions: " << (mCandidateTransactionMap.size() +
248
mActiveTransactionMap.size()));
250
if(mActiveTransactionMap.empty())
255
// CANCEL INVITE branches
256
for (TransactionMap::iterator i = mActiveTransactionMap.begin();
257
i != mActiveTransactionMap.end(); ++i)
259
cancelClientTransaction(i->second);
267
ResponseContext::cancelAllClientTransactions()
270
InfoLog (<< "Cancel ALL client transactions: " << mCandidateTransactionMap.size()
271
<< " pending, " << mActiveTransactionMap.size() << " active.");
273
if(mActiveTransactionMap.empty() && mCandidateTransactionMap.empty())
278
// CANCEL INVITE branches
279
if(mRequestContext.getOriginalRequest().method()==INVITE)
281
for (TransactionMap::iterator i = mActiveTransactionMap.begin();
282
i != mActiveTransactionMap.end(); ++i)
284
cancelClientTransaction(i->second);
288
clearCandidateTransactions();
295
ResponseContext::clearCandidateTransactions()
298
for (TransactionMap::iterator j = mCandidateTransactionMap.begin();
299
j != mCandidateTransactionMap.end();)
302
cancelClientTransaction(j->second);
303
mTerminatedTransactionMap[j->second->tid()] = j->second;
304
TransactionMap::iterator temp = j;
306
mCandidateTransactionMap.erase(temp);
313
ResponseContext::cancelClientTransaction(const resip::Data& tid)
316
TransactionMap::iterator i = mActiveTransactionMap.find(tid);
317
if(mRequestContext.getOriginalRequest().method()==INVITE)
319
if(i!=mActiveTransactionMap.end())
321
cancelClientTransaction(i->second);
326
TransactionMap::iterator j = mCandidateTransactionMap.find(tid);
327
if(j != mCandidateTransactionMap.end())
329
cancelClientTransaction(j->second);
330
mTerminatedTransactionMap[tid] = j->second;
331
mCandidateTransactionMap.erase(j);
339
ResponseContext::getTarget(const resip::Data& tid) const
341
// .bwc. This tid is most likely to be found in either the Candidate targets,
342
// or the Active targets.
343
TransactionMap::const_iterator pend = mCandidateTransactionMap.find(tid);
344
if(pend != mCandidateTransactionMap.end())
346
assert(pend->second->status()==Target::Candidate);
350
TransactionMap::const_iterator act = mActiveTransactionMap.find(tid);
351
if(act != mActiveTransactionMap.end())
353
assert(!(act->second->status()==Target::Candidate || act->second->status()==Target::Terminated));
357
TransactionMap::const_iterator term = mTerminatedTransactionMap.find(tid);
358
if(term != mTerminatedTransactionMap.end())
360
assert(term->second->status()==Target::Terminated);
367
const ResponseContext::TransactionMap&
368
ResponseContext::getCandidateTransactionMap() const
370
return mCandidateTransactionMap;
374
ResponseContext::hasCandidateTransactions() const
376
return !mRequestContext.mHaveSentFinalResponse && !mCandidateTransactionMap.empty();
380
ResponseContext::hasActiveTransactions() const
382
return !mActiveTransactionMap.empty();
386
ResponseContext::hasTerminatedTransactions() const
388
return !mTerminatedTransactionMap.empty();
392
ResponseContext::hasTargets() const
394
return (hasCandidateTransactions() ||
395
hasActiveTransactions() ||
396
hasTerminatedTransactions());
400
ResponseContext::areAllTransactionsTerminated() const
402
return (mCandidateTransactionMap.empty() && mActiveTransactionMap.empty());
406
ResponseContext::isCandidate(const resip::Data& tid) const
408
TransactionMap::const_iterator i=mCandidateTransactionMap.find(tid);
409
return i!=mCandidateTransactionMap.end();
413
ResponseContext::isActive(const resip::Data& tid) const
415
TransactionMap::const_iterator i=mActiveTransactionMap.find(tid);
416
return i!=mActiveTransactionMap.end();
420
ResponseContext::isTerminated(const resip::Data& tid) const
422
TransactionMap::const_iterator i=mTerminatedTransactionMap.find(tid);
423
return i!=mTerminatedTransactionMap.end();
427
ResponseContext::removeClientTransaction(const resip::Data& transactionId)
429
// .bwc. This tid will most likely be found in the map of terminated
430
// transactions, under normal circumstances.
431
// NOTE: This does not remove the corresponding entry in mTargetList.
432
// This is the intended behavior, because the same target should not
433
// be added again later.
435
TransactionMap::iterator i = mTerminatedTransactionMap.find(transactionId);
436
if(i!=mTerminatedTransactionMap.end())
439
mTerminatedTransactionMap.erase(i);
443
i=mCandidateTransactionMap.find(transactionId);
444
if(i!=mCandidateTransactionMap.end())
447
mCandidateTransactionMap.erase(i);
451
i=mActiveTransactionMap.find(transactionId);
452
if(i!=mActiveTransactionMap.end())
455
mActiveTransactionMap.erase(i);
456
WarningLog(<< "Something removed an active transaction, " << transactionId
457
<< ". It is very likely that something is broken here. ");
464
ResponseContext::isDuplicate(const repro::Target* target) const
466
resip::ContactList::const_iterator i;
467
// make sure each target is only inserted once
469
// !bwc! We can not optimize this by using stl, because operator
470
// == does not conform to the partial-ordering established by operator
471
// < (We can very easily have a < b and a==b simultaneously).
472
// [TODO] Once we have a canonicalized form, we can improve this.
474
for(i=mTargetList.begin();i!=mTargetList.end();i++)
476
if(*i==target->rec())
486
ResponseContext::beginClientTransaction(repro::Target* target)
488
// .bwc. This is a private function, and if anything calls this with a
489
// target in an invalid state, it is a bug.
490
assert(target->status() == Target::Candidate);
492
SipMessage& orig=mRequestContext.getOriginalRequest();
493
SipMessage request(orig);
495
// If the target has a ;lr parameter, then perform loose routing
496
if(target->uri().exists(p_lr))
498
request.header(h_Routes).push_front(NameAddr(target->uri()));
502
request.header(h_RequestLine).uri() = target->uri();
505
// .bwc. Proxy checks whether this is valid, and rejects if not.
506
request.header(h_MaxForwards).value()--;
512
inDialog=request.header(h_To).exists(p_tag);
514
catch(resip::ParseException&)
516
// ?bwc? Do we ignore this and just say this is a dialog-creating
520
// Potential source Record-Route addition only for new dialogs
521
// !bwc! It looks like we really ought to be record-routing in-dialog
524
// only add record route if configured to do so
525
if(!mRequestContext.mProxy.getRecordRoute(orig.getReceivedTransport()).uri().host().empty())
527
if (!inDialog && // only for dialog-creating request
528
(request.method() == INVITE ||
529
request.method() == SUBSCRIBE ||
530
request.method() == REFER))
532
insertRecordRoute(request,
533
orig.getReceivedTransport(),
536
else if(request.method()==REGISTER)
538
insertRecordRoute(request,
539
orig.getReceivedTransport(),
541
true /* do Path instead */);
545
if((resip::InteropHelper::getOutboundSupported() ||
546
resip::InteropHelper::getRRTokenHackEnabled() ||
547
mIsClientBehindNAT) &&
548
target->rec().mUseFlowRouting &&
549
target->rec().mReceivedFrom.mFlowKey)
551
// .bwc. We only override the destination if we are sending to an
552
// outbound contact. If this is not an outbound contact, but the
553
// endpoint has given us a Contact with the correct ip-address and
554
// port, we might be able to find the connection they formed when they
555
// registered earlier, but that will happen down in TransportSelector.
556
request.setDestination(target->rec().mReceivedFrom);
559
DebugLog(<<"Set tuple dest: " << request.getDestination());
561
// .bwc. Path header addition.
562
if(!target->rec().mSipPath.empty())
564
request.header(h_Routes).append(target->rec().mSipPath);
567
// a baboon might adorn the message, record call logs or CDRs, might
568
// insert loose routes on the way to the next hop
569
Helper::processStrictRoute(request);
571
//This is where the request acquires the tid of the Target. The tids
572
//should be the same from here on out.
573
request.header(h_Vias).push_front(target->via());
575
if(!mRequestContext.mInitialTimerCSet &&
576
mRequestContext.getOriginalRequest().method()==INVITE)
578
mRequestContext.mInitialTimerCSet=true;
579
mRequestContext.updateTimerC();
582
// the rest of 16.6 is implemented by the transaction layer of resip
583
// - determining the next hop (tuple)
584
// - adding a content-length if needed
585
// - sending the request
586
sendRequest(request);
588
target->status() = Target::Started;
592
ResponseContext::insertRecordRoute(SipMessage& outgoing,
593
const Transport* receivedTransport,
597
resip::Data inboundFlowToken=getInboundFlowToken(doPathInstead);
598
bool needsOutboundFlowToken=outboundFlowTokenNeeded(target);
599
bool recordRouted=false;
600
// .bwc. If we have a flow-token we need to insert, we need to record-route.
601
// Also, we might record-route if we are configured to do so.
602
if( !inboundFlowToken.empty()
603
|| needsOutboundFlowToken
604
|| mRequestContext.mProxy.getRecordRouteForced() )
607
if(inboundFlowToken.empty())
609
rt=mRequestContext.mProxy.getRecordRoute(receivedTransport);
613
if(receivedTransport->getTuple().getType()==TLS ||
614
receivedTransport->getTuple().getType()==DTLS)
616
// .bwc. Debatable. Should we be willing to reuse a TLS connection
617
// at the behest of a Route header with no hostname in it?
618
rt=mRequestContext.mProxy.getRecordRoute(receivedTransport);
619
rt.uri().scheme() = "sips";
623
if(receivedTransport->getTuple().isAnyInterface())
625
rt=mRequestContext.mProxy.getRecordRoute(receivedTransport);
629
rt.uri().host()=resip::Tuple::inet_ntop(receivedTransport->getTuple());
631
rt.uri().port()=receivedTransport->getTuple().getPort();
632
rt.uri().param(resip::p_transport)=resip::Tuple::toDataLower(receivedTransport->getTuple().getType());
634
rt.uri().user()=inboundFlowToken;
636
Helper::massageRoute(outgoing,rt);
639
if(mRequestContext.getProxy().compressionEnabled() &&
640
target->uri().exists(p_comp) &&
641
target->uri().param(p_comp)=="sigcomp")
643
rt.uri().param(p_comp)="sigcomp";
650
if(!inboundFlowToken.empty())
652
// Only add ;ob parameter if client really supports outbound (ie. not for NAT detection mode or flow token hack)
653
if(!mRequestContext.getOriginalRequest().empty(h_Supporteds) &&
654
mRequestContext.getOriginalRequest().header(h_Supporteds).find(Token(Symbols::Outbound)))
656
rt.uri().param(p_ob);
659
outgoing.header(h_Paths).push_front(rt);
660
if(!outgoing.header(h_Supporteds).find(Token("path")))
662
outgoing.header(h_Supporteds).push_back(Token("path"));
664
InfoLog (<< "Added Path: " << rt);
668
outgoing.header(h_RecordRoutes).push_front(rt);
669
InfoLog (<< "Added Record-Route: " << rt);
673
// .bwc. We always need to add this, since we never know if a transport
674
// switch is going to happen. (Except for Path headers; we don't care about
675
// transport switches on REGISTER requests. If we already put a Path header
676
// in, we do care though.)
677
if(!doPathInstead || recordRouted)
679
std::auto_ptr<resip::MessageDecorator> rrDecorator(
680
new RRDecorator(mRequestContext.mProxy,
683
!inboundFlowToken.empty(),
684
mRequestContext.mProxy.getRecordRouteForced(),
686
mIsClientBehindNAT));
687
outgoing.addOutboundDecorator(rrDecorator);
692
ResponseContext::getInboundFlowToken(bool doPathInstead)
694
resip::Data flowToken=resip::Data::Empty;
695
resip::SipMessage& orig=mRequestContext.getOriginalRequest();
696
if(orig.empty(h_Contacts) || !orig.header(h_Contacts).front().isWellFormed())
701
const resip::NameAddr& contact(orig.header(h_Contacts).front());
703
if(InteropHelper::getOutboundSupported() &&
704
(contact.uri().exists(p_ob) || contact.exists(p_regid)))
706
if(orig.header(h_Vias).size()==1)
708
// This arrived over an outbound flow (or so the endpoint claims)
709
// (See outbound-09 Sec 4.3 para 3)
710
resip::Data binaryFlowToken;
711
resip::Tuple source(orig.getSource());
712
source.onlyUseExistingConnection=true;
713
Tuple::writeBinaryToken(source, binaryFlowToken, Proxy::FlowTokenSalt);
714
flowToken = binaryFlowToken.base64encode();
716
else if(doPathInstead)
718
// Need to try to detect Path failures
719
if(orig.empty(h_Paths) || !orig.header(h_Paths).back().uri().exists(p_ob))
721
// Yikes! Client is trying to use outbound, but edge-proxy did not
722
// support it. The registrar will either reject this (if it supports
723
// outbound), or will not indicate outbound support (which should
724
// let the client know that the flow setup failed)
725
WarningLog(<<"Client asked for outbound processing, but the edge "
726
"proxy did not support it. There's nothing we can do to "
727
"salvage this. The registrar might end up rejecting the "
728
"registration (if is supports outbound), or it might just "
729
"fail to add a Supported: outbound. In either case, the "
730
"client should know what's up, so we just let it all "
736
if(flowToken.empty() && orig.header(h_Vias).size()==1)
738
if(resip::InteropHelper::getRRTokenHackEnabled() ||
739
mIsClientBehindNAT ||
740
needsFlowTokenToWork(contact))
742
// !bwc! TODO remove this when flow-token hack is no longer needed.
743
// Poor-man's outbound. Shouldn't be our default behavior, because it
744
// breaks target-refreshes (once a flow-token is in the Route-Set, the
745
// flow-token cannot be changed, and will override any update to the
747
resip::Data binaryFlowToken;
748
Tuple::writeBinaryToken(orig.getSource(), binaryFlowToken, Proxy::FlowTokenSalt);
749
flowToken = binaryFlowToken.base64encode();
757
ResponseContext::outboundFlowTokenNeeded(Target* target)
759
if(mRequestContext.mProxy.isMyUri(target->uri()))
761
// .bwc. We don't need to put flow-tokens pointed at ourselves.
765
if((target->rec().mReceivedFrom.mFlowKey &&
766
target->rec().mUseFlowRouting)
767
|| resip::InteropHelper::getRRTokenHackEnabled()
768
|| mIsClientBehindNAT)
770
target->rec().mReceivedFrom.onlyUseExistingConnection=true;
778
ResponseContext::needsFlowTokenToWork(const resip::NameAddr& contact) const
780
if(DnsUtil::isIpAddress(contact.uri().host()))
782
// IP address in host-part.
783
if(contact.uri().scheme()=="sips")
785
// TLS with no FQDN. Impossible without flow-token fixup, even if no
790
if(contact.uri().exists(p_transport))
792
TransportType type = toTransportType(contact.uri().param(p_transport));
793
if(type==TLS || type == DTLS)
795
// TLS with no FQDN. Impossible without flow-token fixup, even if no
802
if(contact.uri().exists(p_sigcompId))
804
if(contact.uri().exists(p_transport))
806
TransportType type = toTransportType(contact.uri().param(p_transport));
807
if(type == TLS || type == TCP)
809
// Client is using sigcomp on the first hop using a connection-
810
// oriented transport. For this to work, that connection has to be
811
// reused for all traffic.
820
ResponseContext::sendingToSelf(Target* target)
822
if(mRequestContext.mProxy.isMyUri(target->uri()))
830
ResponseContext::sendRequest(resip::SipMessage& request)
832
assert (request.isRequest());
834
if (request.method() != CANCEL &&
835
request.method() != ACK)
837
mRequestContext.getProxy().addClientTransaction(request.getTransactionId(), &mRequestContext);
838
mRequestContext.mTransactionCount++;
839
// if(!mRequestContext.getDigestIdentity().empty())
841
// requestPtr->header(h_Identity);
842
// // !bwc! Need to fill in the Identity-Info header telling where our
843
// // cert can be found.
847
// TODO - P-Asserted-Identity Processing
848
// RFC3325 - section 5
849
// When a proxy forwards a message to another node, it must first
850
// determine if it trusts that node or not. If it trusts the node, the
851
// proxy does not remove any P-Asserted-Identity header fields that it
852
// generated itself, or that it received from a trusted source. If it
853
// does not trust the element, then the proxy MUST examine the Privacy
854
// header field (if present) to determine if the user requested that
855
// asserted identity information be kept private.
857
// Note: Since we have no better mechanism to determine if destination is trusted or
858
// not we will assume that all destinations outside our domain are not-trusted
859
// and will remove the P-Asserted-Identity header, if Privacy is set to "id"
860
if(mRequestContext.getProxy().isPAssertedIdentityProcessingEnabled() &&
861
request.exists(h_Privacies) &&
862
request.header(h_Privacies).size() > 0 &&
863
request.exists(h_PAssertedIdentities) &&
864
!mRequestContext.getProxy().isMyUri(request.header(h_RequestLine).uri()))
866
// Look for "id" token
868
PrivacyCategories::iterator it = request.header(h_Privacies).begin();
869
for(; it != request.header(h_Privacies).end() && !found; it++)
871
std::vector<Data>::iterator itToken = it->value().begin();
872
for(; itToken != it->value().end() && !found; itToken++)
876
request.remove(h_PAssertedIdentities);
883
if (request.method() == ACK)
885
DebugLog(<<"Posting Ack200DoneMessage");
886
mRequestContext.getProxy().post(new Ack200DoneMessage(mRequestContext.getTransactionId()));
889
mRequestContext.send(request);
894
ResponseContext::processCancel(const SipMessage& request)
896
assert(request.isRequest());
897
assert(request.method() == CANCEL);
899
std::auto_ptr<SipMessage> ok(Helper::makeResponse(request, 200));
900
mRequestContext.sendResponse(*ok);
902
if (!mRequestContext.mHaveSentFinalResponse)
904
cancelAllClientTransactions();
905
if(!hasActiveTransactions())
908
Helper::makeResponse(reqterm,mRequestContext.getOriginalRequest(),487);
909
mRequestContext.sendResponse(reqterm);
915
ResponseContext::processTimerC()
917
if (!mRequestContext.mHaveSentFinalResponse)
919
InfoLog(<<"Canceling client transactions due to timer C.");
920
cancelAllClientTransactions();
925
ResponseContext::processResponse(SipMessage& response)
927
InfoLog (<< "processResponse: " << endl << response);
929
// store this before we pop the via and lose the branch tag
930
mCurrentResponseTid = response.getTransactionId();
932
assert (response.isResponse());
933
assert (response.exists(h_Vias) && !response.header(h_Vias).empty());
934
response.header(h_Vias).pop_front();
936
// Stop processing responses that have nowhere else to go
937
if (response.header(h_Vias).empty())
939
// CANCEL/200s only have one Via. Likewise 100s only have one Via
940
// Silently stop processing the CANCEL responses.
941
// We will handle the 100 responses later
942
// Log other responses we can't forward
944
if(response.method()==CANCEL)
948
else if (response.header(h_StatusLine).statusCode() > 199)
950
InfoLog( << "Received final response, but can't forward as there are "
951
"no more Vias. Considering this branch failed. "
952
<< response.brief() );
953
// .bwc. Treat as server error.
954
terminateClientTransaction(mCurrentResponseTid);
957
else if(response.header(h_StatusLine).statusCode() != 100)
959
InfoLog( << "Received provisional response, but can't forward as there"
960
" are no more Vias. Ignoring. " << response.brief() );
964
else // We have a second Via
966
if(!mRequestContext.getOriginalRequest().getRFC2543TransactionId().empty())
968
// .bwc. Original request had an RFC 2543 transaction-id. Set in
970
response.setRFC2543TransactionId(mRequestContext.getOriginalRequest().getRFC2543TransactionId());
973
const Via& via = response.header(h_Vias).front();
975
if(!via.isWellFormed())
977
// .bwc. Garbage via. Unrecoverable. Ignore if provisional, terminate
978
// transaction if not.
979
DebugLog(<<"Some endpoint has corrupted one of our Vias"
980
" in their response. (Via is malformed) This is not fixable.");
981
if(response.header(h_StatusLine).statusCode() > 199)
983
terminateClientTransaction(mCurrentResponseTid);
989
const Via& origVia = mRequestContext.getOriginalRequest().header(h_Vias).front();
990
const Data& branch=(via.exists(p_branch) ? via.param(p_branch).getTransactionId() : Data::Empty);
991
const Data& origBranch=(origVia.exists(p_branch) ? origVia.param(p_branch).getTransactionId() : Data::Empty);
993
if(!isEqualNoCase(branch,origBranch))
995
// .bwc. Someone altered our branch. Ignore if provisional, terminate
996
// transaction otherwise.
997
DebugLog(<<"Some endpoint has altered one of our Vias"
998
" in their response. (branch is different) This is not fixable.");
999
if(response.header(h_StatusLine).statusCode() > 199)
1001
terminateClientTransaction(mCurrentResponseTid);
1008
DebugLog (<< "Search for " << mCurrentResponseTid << " in " << InserterP(mActiveTransactionMap));
1010
TransactionMap::iterator i = mActiveTransactionMap.find(mCurrentResponseTid);
1012
int code = response.header(h_StatusLine).statusCode();
1013
if (i == mActiveTransactionMap.end())
1015
// This is a response for a transaction that is no longer/was never active.
1016
// This is probably a useless response (at best) or a malicious response (at worst).
1017
// Log the response here:
1018
if ((code / 100) != 2)
1020
InfoLog( << "Discarding stray response" );
1022
// Even though this is a tremendously bad idea, some developers may
1023
// decide they want to statelessly forward the response
1024
// Here is the gun. Don't say we didn't warn you!
1027
// !abr! Because we don't run timers on the transaction after
1028
// it has terminated and because the ACKs on INVITE
1029
// 200-class responses are end-to-end, we don't discard
1030
// 200 responses. To do this properly, we should run a
1031
// transaction timer for 64*T1 and remove transactions from
1032
// the ActiveTransactionMap *only* after that timer expires.
1033
// IN OTHER WORDS, REMOVE THIS CODE.
1034
mRequestContext.sendResponse(response);
1042
if(mRequestContext.getOriginalRequest().method()==INVITE)
1044
mRequestContext.updateTimerC();
1047
if (!mRequestContext.mHaveSentFinalResponse)
1051
return; // stop processing 100 responses
1054
mRequestContext.sendResponse(response);
1060
terminateClientTransaction(mCurrentResponseTid);
1061
if (mRequestContext.getOriginalRequest().method() == INVITE)
1063
cancelAllClientTransactions();
1064
mRequestContext.mHaveSentFinalResponse = true;
1065
mBestResponse.header(h_StatusLine).statusCode()=
1066
response.header(h_StatusLine).statusCode();
1067
mRequestContext.sendResponse(response);
1069
else if (!mRequestContext.mHaveSentFinalResponse)
1071
clearCandidateTransactions();
1072
mRequestContext.mHaveSentFinalResponse = true;
1073
mBestResponse.header(h_StatusLine).statusCode()=
1074
response.header(h_StatusLine).statusCode();
1076
// If this is a registration response and we have flow timers enabled, and
1077
// we are doing outbound for this registration and there is no FlowTimer
1078
// header present already, then add a FlowTimer header
1079
if(response.method() == REGISTER &&
1080
InteropHelper::getFlowTimerSeconds() > 0 &&
1081
response.empty(h_FlowTimer) &&
1082
((!response.empty(h_Paths) && response.header(h_Paths).back().uri().exists(p_ob)) ||
1083
(!response.empty(h_Requires) && response.header(h_Requires).find(Token(Symbols::Outbound)))))
1085
response.header(h_FlowTimer).value() = InteropHelper::getFlowTimerSeconds();
1086
mRequestContext.getProxy().getStack().enableFlowTimer(mRequestContext.getOriginalRequest().getSource());
1089
mRequestContext.sendResponse(response);
1096
DebugLog (<< "forwardedFinal=" << mRequestContext.mHaveSentFinalResponse
1097
<< " outstanding client transactions: " << InserterP(mActiveTransactionMap));
1098
terminateClientTransaction(mCurrentResponseTid);
1099
if (!mRequestContext.mHaveSentFinalResponse)
1101
int priority = getPriority(response);
1102
if (priority == mBestPriority)
1104
if (code == 401 || code == 407)
1106
if (response.exists(h_WWWAuthenticates))
1108
for ( Auths::iterator i=response.header(h_WWWAuthenticates).begin();
1109
i != response.header(h_WWWAuthenticates).end() ; ++i)
1111
mBestResponse.header(h_WWWAuthenticates).push_back(*i);
1115
if (response.exists(h_ProxyAuthenticates))
1117
for ( Auths::iterator i=response.header(h_ProxyAuthenticates).begin();
1118
i != response.header(h_ProxyAuthenticates).end() ; ++i)
1120
mBestResponse.header(h_ProxyAuthenticates).push_back(*i);
1122
mBestResponse.header(h_StatusLine).statusCode() = 407;
1125
else if (code / 100 == 3) // merge 3xx
1128
if(mBestResponse.header(h_StatusLine).statusCode()/100!=3)
1130
// .bwc. Do not merge contacts in 3xx with contacts from a
1131
// previous 4xx or 5xx
1132
mBestResponse.header(h_Contacts).clear();
1135
for (NameAddrs::iterator i=response.header(h_Contacts).begin();
1136
i != response.header(h_Contacts).end(); ++i)
1138
// TODO ?bwc? if we are going to be checking whether
1139
// this is "*", we should see if it is well-formed
1140
// first. If we shouldn't be doing any checks on
1141
// the contacts, we should simply remove all of this
1142
// checking code and just blindly copy the contacts over.
1144
if(!i->isWellFormed() || i->isAllContacts())
1146
// .bwc. Garbage contact; ignore it.
1150
mBestResponse.header(h_Contacts).push_back(*i);
1153
// ?bwc? it is possible for this code to end up with a 300
1154
// with no Contacts in it (because they were all malformed)
1155
// Is this acceptable? Also, is 300 the code we want here?
1156
mBestResponse.header(h_StatusLine).statusCode() = 300;
1159
else if (priority < mBestPriority)
1161
mBestPriority = priority;
1162
mBestResponse = response;
1165
if (areAllTransactionsTerminated())
1167
forwardBestResponse();
1173
terminateClientTransaction(mCurrentResponseTid);
1174
if (!mRequestContext.mHaveSentFinalResponse)
1176
if (mBestResponse.header(h_StatusLine).statusCode() / 100 != 6)
1178
mBestResponse = response;
1179
mBestPriority=0; //6xx class responses take precedence over all 3xx,4xx, and 5xx
1180
if (mRequestContext.getOriginalRequest().method() == INVITE)
1182
// CANCEL INVITE branches
1183
cancelAllClientTransactions();
1187
if (areAllTransactionsTerminated())
1189
forwardBestResponse();
1201
ResponseContext::cancelClientTransaction(repro::Target* target)
1203
if (target->status() == Target::Started)
1205
InfoLog (<< "Cancel client transaction: " << target);
1206
mRequestContext.cancelClientTransaction(target->via().param(p_branch).getTransactionId());
1208
DebugLog(<< "Canceling a transaction with uri: "
1209
<< resip::Data::from(target->uri()) << " , to host: "
1210
<< target->via().sentHost());
1211
target->status() = Target::Cancelled;
1213
else if (target->status() == Target::Candidate)
1215
target->status() = Target::Terminated;
1220
ResponseContext::terminateClientTransaction(const resip::Data& tid)
1223
InfoLog (<< "Terminating client transaction: " << tid << " all = " << areAllTransactionsTerminated());
1225
TransactionMap::iterator i = mActiveTransactionMap.find(tid);
1226
if(i != mActiveTransactionMap.end())
1228
InfoLog (<< "client transactions: " << InserterP(mActiveTransactionMap));
1229
i->second->status() = Target::Terminated;
1230
mTerminatedTransactionMap[tid] = i->second;
1231
mActiveTransactionMap.erase(i);
1235
TransactionMap::iterator j = mCandidateTransactionMap.find(tid);
1236
if(j != mCandidateTransactionMap.end())
1238
InfoLog (<< "client transactions: " << InserterP(mCandidateTransactionMap));
1239
j->second->status() = Target::Terminated;
1240
mTerminatedTransactionMap[tid] = j->second;
1241
mCandidateTransactionMap.erase(j);
1249
ResponseContext::getPriority(const resip::SipMessage& msg)
1251
int responseCode = msg.header(h_StatusLine).statusCode();
1252
int p = 0; // "p" is the relative priority of the response
1254
assert(responseCode >= 300 && responseCode <= 599);
1255
if (responseCode <= 399) // 3xx response
1257
return 5; // response priority is 5
1259
if (responseCode >= 500)
1261
switch(responseCode)
1263
case 501: // these four have different priorities
1264
case 503: // which are addressed in the case statement
1265
case 580: // below (with the 4xx responses)
1269
return 42; // response priority of other 5xx is 42
1273
switch(responseCode)
1275
// Easy to Repair Responses: 412, 484, 422, 423, 407, 401, 300..399, 402
1276
case 412: // Publish ETag was stale
1278
case 484: // overlap dialing
1280
case 422: // Session-Timer duration too long
1281
case 423: // Expires too short
1283
case 407: // Proxy-Auth
1284
case 401: // UA Digest challenge
1287
// 3xx responses have p = 5
1288
case 402: // Payment required
1291
// Responses used for negotiation: 493, 429, 420, 406, 415, 488
1292
case 493: // Undecipherable, try again unencrypted
1295
case 420: // Required Extension not supported, try again without
1298
case 406: // Not Acceptable
1299
case 415: // Unsupported Media Type
1300
case 488: // Not Acceptable Here
1303
// Possibly useful for negotiation, but less likely: 421, 416, 417, 494, 580, 485, 405, 501, 413, 414
1305
case 416: // Unsupported scheme
1306
case 417: // Unknown Resource-Priority
1309
case 405: // Method not allowed (both used for negotiating REFER, PUBLISH, etc..
1310
case 501: // Usually used when the method is not OK
1313
case 580: // Preconditions failure
1316
case 485: // Ambiguous userpart. A bit better than 404?
1319
case 428: // Use Identity header
1320
case 429: // Provide Referrer Identity
1321
case 494: // Use the sec-agree mechanism
1324
case 413: // Request too big
1325
case 414: // URI too big
1328
case 421: // An extension required by the server was not in the Supported header
1331
// The request isn't repairable, but at least we can try to provide some
1332
// useful information: 486, 480, 410, 404, 403, 487
1334
case 486: // Busy Here
1337
case 480: // Temporarily unavailable
1343
case 436: // Bad Identity-Info
1344
case 437: // Unsupported Certificate
1345
case 513: // Message too large
1348
case 403: // Forbidden
1351
case 404: // Not Found
1354
case 487: // Some branches were cancelled, if the UAC sent a CANCEL this is good news
1357
// We are hosed: 503, 483, 482, 481, other 5xx, 400, 491, 408 // totally useless
1359
case 503: // bad news, we should never forward this back anyway
1362
case 483: // loops, encountered
1368
// UAS is seriously confused: p = 43
1374
case 408: // very, very bad (even worse than the remaining 4xx responses)
1384
ResponseContext::CompareStatus::operator()(const resip::SipMessage& lhs, const resip::SipMessage& rhs) const
1386
assert(lhs.isResponse());
1387
assert(rhs.isResponse());
1389
// !rwm! replace with correct thingy here
1390
return lhs.header(h_StatusLine).statusCode() < rhs.header(h_StatusLine).statusCode();
1394
ResponseContext::forwardBestResponse()
1396
InfoLog (<< "Forwarding best response: " << mBestResponse.brief());
1398
clearCandidateTransactions();
1400
if(mRequestContext.getOriginalRequest().method()==INVITE)
1402
cancelActiveClientTransactions();
1405
if(mBestResponse.header(h_StatusLine).statusCode() == 503)
1407
//See RFC 3261 sec 16.7, page 110, paragraph 2
1408
mBestResponse.header(h_StatusLine).statusCode() = 480;
1411
if(mBestResponse.header(h_StatusLine).statusCode() == 408 &&
1412
mBestResponse.method()!=INVITE)
1414
// We don't forward back NIT 408; we just silently abandon the transaction - RFC4321 - section 1.4 408 for non-INVITE is not useful
1415
DebugLog(<< "Got NIT 408, abandoning: "<<mRequestContext.getTransactionId());
1416
mRequestContext.getProxy().getStack().abandonServerTransaction(mRequestContext.getTransactionId());
1417
mRequestContext.mHaveSentFinalResponse = true; // To avoid Request context from sending a response
1421
mRequestContext.sendResponse(mBestResponse);
1426
repro::operator<<(EncodeStream& strm, const ResponseContext& rc)
1428
strm << "ResponseContext: "
1429
<< " identity=" << rc.mRequestContext.getDigestIdentity()
1430
<< " best=" << rc.mBestPriority << " " << rc.mBestResponse.brief()
1431
<< " forwarded=" << rc.mRequestContext.mHaveSentFinalResponse
1432
<< " pending=" << InserterP(rc.mCandidateTransactionMap)
1433
<< " active=" << InserterP(rc.mActiveTransactionMap)
1434
<< " terminated=" << InserterP(rc.mTerminatedTransactionMap);
1440
/* ====================================================================
1441
* The Vovida Software License, Version 1.0
1443
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1445
* Redistribution and use in source and binary forms, with or without
1446
* modification, are permitted provided that the following conditions
1449
* 1. Redistributions of source code must retain the above copyright
1450
* notice, this list of conditions and the following disclaimer.
1452
* 2. Redistributions in binary form must reproduce the above copyright
1453
* notice, this list of conditions and the following disclaimer in
1454
* the documentation and/or other materials provided with the
1457
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
1458
* and "Vovida Open Communication Application Library (VOCAL)" must
1459
* not be used to endorse or promote products derived from this
1460
* software without prior written permission. For written
1461
* permission, please contact vocal@vovida.org.
1463
* 4. Products derived from this software may not be called "VOCAL", nor
1464
* may "VOCAL" appear in their name, without prior written
1465
* permission of Vovida Networks, Inc.
1467
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1468
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1469
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1470
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1471
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1472
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1473
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1474
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1475
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1476
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1477
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1478
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1481
* ====================================================================
1483
* This software consists of voluntary contributions made by Vovida
1484
* Networks, Inc. and many individuals on behalf of Vovida Networks,
1485
* Inc. For more information on Vovida Networks, Inc., please see
1486
* <http://www.vovida.org/>.