~ubuntu-branches/ubuntu/saucy/resiprocate/saucy-proposed

« back to all changes in this revision

Viewing changes to repro/ResponseContext.cxx

  • Committer: Package Import Robot
  • Author(s): Daniel Pocock
  • Date: 2012-05-17 19:29:59 UTC
  • Revision ID: package-import@ubuntu.com-20120517192959-vv00m77isztdy64q
Tags: upstream-1.8.2
ImportĀ upstreamĀ versionĀ 1.8.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#if defined(HAVE_CONFIG_H)
 
2
#include "config.h"
 
3
#endif
 
4
 
 
5
#include <iostream>
 
6
 
 
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"
 
21
 
 
22
#define RESIPROCATE_SUBSYSTEM resip::Subsystem::REPRO
 
23
 
 
24
using namespace resip;
 
25
using namespace repro;
 
26
using namespace std;
 
27
 
 
28
ResponseContext::ResponseContext(RequestContext& context) : 
 
29
   mRequestContext(context),
 
30
   mBestPriority(50),
 
31
   mSecure(false), //context.getOriginalRequest().header(h_RequestLine).uri().scheme() == Symbols::Sips)
 
32
   mIsClientBehindNAT(false)
 
33
{
 
34
}
 
35
 
 
36
 
 
37
ResponseContext::~ResponseContext()
 
38
{
 
39
   TransactionMap::iterator i;
 
40
   
 
41
   for(i=mTerminatedTransactionMap.begin(); i!=mTerminatedTransactionMap.end();++i)
 
42
   {
 
43
      delete i->second;
 
44
   }
 
45
   mTerminatedTransactionMap.clear();
 
46
   
 
47
   for(i=mActiveTransactionMap.begin(); i!=mActiveTransactionMap.end();++i)
 
48
   {
 
49
      delete i->second;
 
50
   }
 
51
   mActiveTransactionMap.clear();
 
52
   
 
53
   for(i=mCandidateTransactionMap.begin(); i!=mCandidateTransactionMap.end();++i)
 
54
   {
 
55
      delete i->second;
 
56
   }
 
57
   mCandidateTransactionMap.clear();
 
58
}
 
59
 
 
60
resip::Data
 
61
ResponseContext::addTarget(const NameAddr& addr, bool beginImmediately)
 
62
{
 
63
   InfoLog (<< "Adding candidate " << addr);
 
64
   std::auto_ptr<Target> target(new Target(addr));
 
65
   Data tid=target->tid();
 
66
   addTarget(target, beginImmediately);
 
67
   return tid;
 
68
}
 
69
 
 
70
bool
 
71
ResponseContext::addTarget(std::auto_ptr<repro::Target> target, bool beginImmediately)
 
72
{
 
73
   if(mRequestContext.mHaveSentFinalResponse || !target.get())
 
74
   {
 
75
      return false;
 
76
   }
 
77
 
 
78
   //Disallow sip: if secure
 
79
   if(mSecure && target->uri().scheme() != Symbols::Sips)
 
80
   {
 
81
      return false;
 
82
   }
 
83
   
 
84
   //Make sure we don't have Targets with an invalid initial state.
 
85
   if(target->status() != Target::Candidate)
 
86
   {
 
87
      return false;
 
88
   }
 
89
   
 
90
   if(beginImmediately)
 
91
   {
 
92
      if(isDuplicate(target.get()))
 
93
      {
 
94
         return false;
 
95
      }
 
96
   
 
97
      mTargetList.push_back(target->rec());
 
98
      
 
99
      beginClientTransaction(target.get());
 
100
      target->status()=Target::Started;
 
101
      Target* toAdd=target.release();
 
102
      mActiveTransactionMap[toAdd->tid()]=toAdd;
 
103
   }
 
104
   else
 
105
   {
 
106
      if(target->mShouldAutoProcess)  // note: for base repro - this is always true
 
107
      {
 
108
         std::list<resip::Data> queue;
 
109
         queue.push_back(target->tid());
 
110
         mTransactionQueueCollection.push_back(queue);
 
111
      }
 
112
 
 
113
      Target* toAdd=target.release();
 
114
      mCandidateTransactionMap[toAdd->tid()]=toAdd;
 
115
   }
 
116
   
 
117
   return true;
 
118
}
 
119
 
 
120
bool
 
121
ResponseContext::addTargetBatch(TargetPtrList& targets,
 
122
                                bool highPriority)
 
123
{
 
124
   std::list<resip::Data> queue;
 
125
   Target* target=0;
 
126
   TargetPtrList::iterator it;
 
127
 
 
128
   if(mRequestContext.mHaveSentFinalResponse || targets.empty())
 
129
   {
 
130
      for(it=targets.begin();it!=targets.end();it++)
 
131
      {
 
132
         delete *it;
 
133
      }
 
134
      
 
135
      targets.clear();
 
136
      return false;
 
137
   }
 
138
 
 
139
   for(it=targets.begin();it!=targets.end();it++)
 
140
   {
 
141
      target=*it;
 
142
      
 
143
      if((!mSecure || target->uri().scheme() == Symbols::Sips) &&
 
144
         target->status() == Target::Candidate)
 
145
      {
 
146
         if(target->mShouldAutoProcess)
 
147
         {
 
148
            queue.push_back(target->tid());
 
149
         }
 
150
         DebugLog(<<"Adding Target to Candidates: " << target->uri() << " tid=" << target->tid());
 
151
         mCandidateTransactionMap[target->tid()]=target;
 
152
      }
 
153
      else
 
154
      {
 
155
         DebugLog(<<"Bad Target: " << target->uri());
 
156
         delete target;
 
157
      }
 
158
   }
 
159
 
 
160
   targets.clear();
 
161
   
 
162
   if(highPriority)  // note: for base repro - this is always false
 
163
   {
 
164
      mTransactionQueueCollection.push_front(queue);
 
165
   }
 
166
   else
 
167
   {
 
168
      mTransactionQueueCollection.push_back(queue);
 
169
   }
 
170
   
 
171
   return true;
 
172
}
 
173
 
 
174
bool 
 
175
ResponseContext::beginClientTransactions()
 
176
{
 
177
   bool result=false;
 
178
   
 
179
   if(mCandidateTransactionMap.empty())
 
180
   {
 
181
      return result;
 
182
   }
 
183
   
 
184
   for (TransactionMap::iterator i=mCandidateTransactionMap.begin(); i != mCandidateTransactionMap.end(); )
 
185
   {
 
186
      if(!isDuplicate(i->second) && !mRequestContext.mHaveSentFinalResponse)
 
187
      {
 
188
         mTargetList.push_back(i->second->rec());  // Add to Target list for future duplicate detection
 
189
         beginClientTransaction(i->second);
 
190
         result=true;
 
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());
 
196
      }
 
197
      else
 
198
      {
 
199
         i->second->status() = Target::Terminated;
 
200
         mTerminatedTransactionMap[i->second->tid()] = i->second;
 
201
         DebugLog(<<"Found a repeated target.");
 
202
      }
 
203
      
 
204
      TransactionMap::iterator temp=i;
 
205
      i++;
 
206
      mCandidateTransactionMap.erase(temp);
 
207
   }
 
208
   
 
209
   return result;
 
210
}
 
211
 
 
212
bool 
 
213
ResponseContext::beginClientTransaction(const resip::Data& tid)
 
214
{
 
215
   TransactionMap::iterator i = mCandidateTransactionMap.find(tid);
 
216
   if(i==mCandidateTransactionMap.end())
 
217
   {
 
218
      return false;
 
219
   }
 
220
   
 
221
   if(isDuplicate(i->second) || mRequestContext.mHaveSentFinalResponse)
 
222
   {
 
223
      i->second->status() = Target::Terminated;
 
224
      mTerminatedTransactionMap[i->second->tid()] = i->second;
 
225
      mCandidateTransactionMap.erase(i);
 
226
      return false;
 
227
   }
 
228
   
 
229
   mTargetList.push_back(i->second->rec()); // Add to Target list for future duplicate detection
 
230
 
 
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);
 
235
   
 
236
   return true;
 
237
}
 
238
 
 
239
bool 
 
240
ResponseContext::cancelActiveClientTransactions()
 
241
{
 
242
   if(mRequestContext.mHaveSentFinalResponse)
 
243
   {
 
244
      return false;
 
245
   }
 
246
 
 
247
   InfoLog (<< "Cancel all proceeding client transactions: " << (mCandidateTransactionMap.size() + 
 
248
            mActiveTransactionMap.size()));
 
249
 
 
250
   if(mActiveTransactionMap.empty())
 
251
   {
 
252
      return false;
 
253
   }
 
254
 
 
255
   // CANCEL INVITE branches
 
256
   for (TransactionMap::iterator i = mActiveTransactionMap.begin(); 
 
257
        i != mActiveTransactionMap.end(); ++i)
 
258
   {
 
259
      cancelClientTransaction(i->second);
 
260
   }
 
261
      
 
262
   return true;
 
263
 
 
264
}
 
265
 
 
266
bool
 
267
ResponseContext::cancelAllClientTransactions()
 
268
{
 
269
 
 
270
   InfoLog (<< "Cancel ALL client transactions: " << mCandidateTransactionMap.size()
 
271
            << " pending, " << mActiveTransactionMap.size() << " active.");
 
272
 
 
273
   if(mActiveTransactionMap.empty() && mCandidateTransactionMap.empty())
 
274
   {
 
275
      return false;
 
276
   }
 
277
 
 
278
   // CANCEL INVITE branches
 
279
   if(mRequestContext.getOriginalRequest().method()==INVITE)
 
280
   {
 
281
      for (TransactionMap::iterator i = mActiveTransactionMap.begin(); 
 
282
           i != mActiveTransactionMap.end(); ++i)
 
283
      {
 
284
         cancelClientTransaction(i->second);
 
285
      }
 
286
   }
 
287
 
 
288
   clearCandidateTransactions();
 
289
   
 
290
   return true;
 
291
 
 
292
}
 
293
 
 
294
bool
 
295
ResponseContext::clearCandidateTransactions()
 
296
{
 
297
   bool result=false;
 
298
   for (TransactionMap::iterator j = mCandidateTransactionMap.begin(); 
 
299
        j != mCandidateTransactionMap.end();)
 
300
   {
 
301
      result=true;
 
302
      cancelClientTransaction(j->second);
 
303
      mTerminatedTransactionMap[j->second->tid()] = j->second;
 
304
      TransactionMap::iterator temp = j;
 
305
      j++;
 
306
      mCandidateTransactionMap.erase(temp);
 
307
   }
 
308
   
 
309
   return result;
 
310
}
 
311
 
 
312
bool 
 
313
ResponseContext::cancelClientTransaction(const resip::Data& tid)
 
314
{
 
315
 
 
316
   TransactionMap::iterator i = mActiveTransactionMap.find(tid);
 
317
   if(mRequestContext.getOriginalRequest().method()==INVITE)
 
318
   {
 
319
      if(i!=mActiveTransactionMap.end())
 
320
      {
 
321
         cancelClientTransaction(i->second);      
 
322
         return true;
 
323
      }
 
324
   }
 
325
   
 
326
   TransactionMap::iterator j = mCandidateTransactionMap.find(tid);
 
327
   if(j != mCandidateTransactionMap.end())
 
328
   {
 
329
      cancelClientTransaction(j->second);
 
330
      mTerminatedTransactionMap[tid] = j->second;
 
331
      mCandidateTransactionMap.erase(j);
 
332
      return true;
 
333
   }
 
334
   
 
335
   return false;
 
336
}
 
337
 
 
338
Target* 
 
339
ResponseContext::getTarget(const resip::Data& tid) const
 
340
{
 
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())
 
345
   {
 
346
      assert(pend->second->status()==Target::Candidate);
 
347
      return pend->second;
 
348
   }
 
349
   
 
350
   TransactionMap::const_iterator act = mActiveTransactionMap.find(tid);
 
351
   if(act != mActiveTransactionMap.end())
 
352
   {
 
353
      assert(!(act->second->status()==Target::Candidate || act->second->status()==Target::Terminated));
 
354
      return act->second;
 
355
   }
 
356
 
 
357
   TransactionMap::const_iterator term = mTerminatedTransactionMap.find(tid);
 
358
   if(term != mTerminatedTransactionMap.end())
 
359
   {
 
360
      assert(term->second->status()==Target::Terminated);
 
361
      return term->second;
 
362
   }
 
363
 
 
364
   return 0;
 
365
}
 
366
 
 
367
const ResponseContext::TransactionMap& 
 
368
ResponseContext::getCandidateTransactionMap() const
 
369
{
 
370
   return mCandidateTransactionMap;
 
371
}
 
372
 
 
373
bool 
 
374
ResponseContext::hasCandidateTransactions() const
 
375
{
 
376
   return !mRequestContext.mHaveSentFinalResponse && !mCandidateTransactionMap.empty();
 
377
}
 
378
 
 
379
bool 
 
380
ResponseContext::hasActiveTransactions() const
 
381
{
 
382
   return !mActiveTransactionMap.empty();
 
383
}
 
384
 
 
385
bool 
 
386
ResponseContext::hasTerminatedTransactions() const
 
387
{
 
388
   return !mTerminatedTransactionMap.empty();
 
389
}
 
390
 
 
391
bool
 
392
ResponseContext::hasTargets() const
 
393
{
 
394
   return (hasCandidateTransactions() ||
 
395
            hasActiveTransactions() ||
 
396
            hasTerminatedTransactions());
 
397
}
 
398
 
 
399
bool 
 
400
ResponseContext::areAllTransactionsTerminated() const
 
401
{
 
402
   return (mCandidateTransactionMap.empty() && mActiveTransactionMap.empty());
 
403
}
 
404
 
 
405
bool
 
406
ResponseContext::isCandidate(const resip::Data& tid) const
 
407
{
 
408
   TransactionMap::const_iterator i=mCandidateTransactionMap.find(tid);
 
409
   return i!=mCandidateTransactionMap.end();
 
410
}
 
411
 
 
412
bool
 
413
ResponseContext::isActive(const resip::Data& tid) const
 
414
{
 
415
   TransactionMap::const_iterator i=mActiveTransactionMap.find(tid);
 
416
   return i!=mActiveTransactionMap.end();
 
417
}
 
418
 
 
419
bool
 
420
ResponseContext::isTerminated(const resip::Data& tid) const
 
421
{
 
422
   TransactionMap::const_iterator i=mTerminatedTransactionMap.find(tid);
 
423
   return i!=mTerminatedTransactionMap.end();
 
424
}
 
425
 
 
426
void 
 
427
ResponseContext::removeClientTransaction(const resip::Data& transactionId)
 
428
{
 
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.
 
434
 
 
435
   TransactionMap::iterator i = mTerminatedTransactionMap.find(transactionId);
 
436
   if(i!=mTerminatedTransactionMap.end())
 
437
   {
 
438
      delete i->second;
 
439
      mTerminatedTransactionMap.erase(i);
 
440
      return;
 
441
   }
 
442
 
 
443
   i=mCandidateTransactionMap.find(transactionId);
 
444
   if(i!=mCandidateTransactionMap.end())
 
445
   {
 
446
      delete i->second;
 
447
      mCandidateTransactionMap.erase(i);
 
448
      return;
 
449
   }
 
450
   
 
451
   i=mActiveTransactionMap.find(transactionId);
 
452
   if(i!=mActiveTransactionMap.end())
 
453
   {
 
454
      delete i->second;
 
455
      mActiveTransactionMap.erase(i);
 
456
      WarningLog(<< "Something removed an active transaction, " << transactionId
 
457
               << ". It is very likely that something is broken here. ");
 
458
      return;
 
459
   }
 
460
         
 
461
}
 
462
 
 
463
bool
 
464
ResponseContext::isDuplicate(const repro::Target* target) const
 
465
{
 
466
   resip::ContactList::const_iterator i;
 
467
   // make sure each target is only inserted once
 
468
 
 
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.
 
473
 
 
474
   for(i=mTargetList.begin();i!=mTargetList.end();i++)
 
475
   {
 
476
      if(*i==target->rec())
 
477
      {
 
478
         return true;
 
479
      }
 
480
   }
 
481
 
 
482
   return false;
 
483
}
 
484
 
 
485
void
 
486
ResponseContext::beginClientTransaction(repro::Target* target)
 
487
{
 
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);
 
491
 
 
492
   SipMessage& orig=mRequestContext.getOriginalRequest();
 
493
   SipMessage request(orig);
 
494
 
 
495
   // If the target has a ;lr parameter, then perform loose routing
 
496
   if(target->uri().exists(p_lr))
 
497
   {
 
498
      request.header(h_Routes).push_front(NameAddr(target->uri()));
 
499
   }
 
500
   else
 
501
   {
 
502
      request.header(h_RequestLine).uri() = target->uri();
 
503
   }
 
504
 
 
505
   // .bwc. Proxy checks whether this is valid, and rejects if not.
 
506
   request.header(h_MaxForwards).value()--;
 
507
   
 
508
   bool inDialog=false;
 
509
   
 
510
   try
 
511
   {
 
512
      inDialog=request.header(h_To).exists(p_tag);
 
513
   }
 
514
   catch(resip::ParseException&)
 
515
   {
 
516
      // ?bwc? Do we ignore this and just say this is a dialog-creating
 
517
      // request?
 
518
   }
 
519
   
 
520
   // Potential source Record-Route addition only for new dialogs
 
521
   // !bwc! It looks like we really ought to be record-routing in-dialog
 
522
   // stuff.
 
523
 
 
524
   // only add record route if configured to do so
 
525
   if(!mRequestContext.mProxy.getRecordRoute(orig.getReceivedTransport()).uri().host().empty())
 
526
   {
 
527
      if (!inDialog &&  // only for dialog-creating request
 
528
          (request.method() == INVITE ||
 
529
           request.method() == SUBSCRIBE ||
 
530
           request.method() == REFER))
 
531
      {
 
532
         insertRecordRoute(request,
 
533
                           orig.getReceivedTransport(),
 
534
                           target);
 
535
      }
 
536
      else if(request.method()==REGISTER)
 
537
      {
 
538
         insertRecordRoute(request,
 
539
                           orig.getReceivedTransport(),
 
540
                           target,
 
541
                           true /* do Path instead */);
 
542
      }
 
543
   }
 
544
      
 
545
   if((resip::InteropHelper::getOutboundSupported() ||
 
546
       resip::InteropHelper::getRRTokenHackEnabled() ||
 
547
       mIsClientBehindNAT) &&
 
548
      target->rec().mUseFlowRouting &&
 
549
      target->rec().mReceivedFrom.mFlowKey)
 
550
   {
 
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);
 
557
   }
 
558
 
 
559
   DebugLog(<<"Set tuple dest: " << request.getDestination());
 
560
 
 
561
   // .bwc. Path header addition.
 
562
   if(!target->rec().mSipPath.empty())
 
563
   {
 
564
      request.header(h_Routes).append(target->rec().mSipPath);
 
565
   }
 
566
 
 
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);
 
570
   
 
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());
 
574
 
 
575
   if(!mRequestContext.mInitialTimerCSet &&
 
576
      mRequestContext.getOriginalRequest().method()==INVITE)
 
577
   {
 
578
      mRequestContext.mInitialTimerCSet=true;
 
579
      mRequestContext.updateTimerC();
 
580
   }
 
581
   
 
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); 
 
587
 
 
588
   target->status() = Target::Started;
 
589
}
 
590
 
 
591
void
 
592
ResponseContext::insertRecordRoute(SipMessage& outgoing,
 
593
                                   const Transport* receivedTransport,
 
594
                                   Target* target,
 
595
                                   bool doPathInstead)
 
596
{
 
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() )
 
605
   {
 
606
      resip::NameAddr rt;
 
607
      if(inboundFlowToken.empty())
 
608
      {
 
609
         rt=mRequestContext.mProxy.getRecordRoute(receivedTransport);
 
610
      }
 
611
      else
 
612
      {
 
613
         if(receivedTransport->getTuple().getType()==TLS || 
 
614
            receivedTransport->getTuple().getType()==DTLS)
 
615
         {
 
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";
 
620
         }
 
621
         else
 
622
         {
 
623
            if(receivedTransport->getTuple().isAnyInterface())
 
624
            {
 
625
               rt=mRequestContext.mProxy.getRecordRoute(receivedTransport);
 
626
            }
 
627
            else
 
628
            {
 
629
               rt.uri().host()=resip::Tuple::inet_ntop(receivedTransport->getTuple());
 
630
            }
 
631
            rt.uri().port()=receivedTransport->getTuple().getPort();
 
632
            rt.uri().param(resip::p_transport)=resip::Tuple::toDataLower(receivedTransport->getTuple().getType());
 
633
         }
 
634
         rt.uri().user()=inboundFlowToken;
 
635
      }
 
636
      Helper::massageRoute(outgoing,rt);
 
637
 
 
638
#ifdef USE_SIGCOMP
 
639
      if(mRequestContext.getProxy().compressionEnabled() &&
 
640
         target->uri().exists(p_comp) &&
 
641
         target->uri().param(p_comp)=="sigcomp")
 
642
      {
 
643
         rt.uri().param(p_comp)="sigcomp";
 
644
      }
 
645
#endif
 
646
 
 
647
      recordRouted=true;
 
648
      if(doPathInstead)
 
649
      {
 
650
         if(!inboundFlowToken.empty())
 
651
         {
 
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)))
 
655
            {
 
656
               rt.uri().param(p_ob);
 
657
            }
 
658
         }
 
659
         outgoing.header(h_Paths).push_front(rt);
 
660
         if(!outgoing.header(h_Supporteds).find(Token("path")))
 
661
         {
 
662
            outgoing.header(h_Supporteds).push_back(Token("path"));
 
663
         }
 
664
         InfoLog (<< "Added Path: " << rt);
 
665
      }
 
666
      else
 
667
      {
 
668
         outgoing.header(h_RecordRoutes).push_front(rt);
 
669
         InfoLog (<< "Added Record-Route: " << rt);
 
670
      }
 
671
   }
 
672
 
 
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)
 
678
   {
 
679
      std::auto_ptr<resip::MessageDecorator> rrDecorator(
 
680
                                 new RRDecorator(mRequestContext.mProxy,
 
681
                                                receivedTransport,
 
682
                                                recordRouted,
 
683
                                                !inboundFlowToken.empty(),
 
684
                                                mRequestContext.mProxy.getRecordRouteForced(),
 
685
                                                doPathInstead,
 
686
                                                mIsClientBehindNAT));
 
687
      outgoing.addOutboundDecorator(rrDecorator);
 
688
   }
 
689
}
 
690
 
 
691
resip::Data
 
692
ResponseContext::getInboundFlowToken(bool doPathInstead)
 
693
{
 
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())
 
697
   {
 
698
      return flowToken;
 
699
   }
 
700
 
 
701
   const resip::NameAddr& contact(orig.header(h_Contacts).front());
 
702
 
 
703
   if(InteropHelper::getOutboundSupported() && 
 
704
      (contact.uri().exists(p_ob) || contact.exists(p_regid)))
 
705
   {
 
706
      if(orig.header(h_Vias).size()==1)
 
707
      {
 
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();
 
715
      }
 
716
      else if(doPathInstead)
 
717
      {
 
718
         // Need to try to detect Path failures
 
719
         if(orig.empty(h_Paths) || !orig.header(h_Paths).back().uri().exists(p_ob))
 
720
         {
 
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 "
 
731
                     "happen.");
 
732
         }
 
733
      }
 
734
   }
 
735
 
 
736
   if(flowToken.empty() && orig.header(h_Vias).size()==1)
 
737
   {
 
738
      if(resip::InteropHelper::getRRTokenHackEnabled() ||
 
739
         mIsClientBehindNAT ||
 
740
         needsFlowTokenToWork(contact))
 
741
      {
 
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 
 
746
         // Contact)
 
747
         resip::Data binaryFlowToken;
 
748
         Tuple::writeBinaryToken(orig.getSource(), binaryFlowToken, Proxy::FlowTokenSalt);
 
749
         flowToken = binaryFlowToken.base64encode();
 
750
      }
 
751
   }
 
752
 
 
753
   return flowToken;
 
754
}
 
755
 
 
756
bool
 
757
ResponseContext::outboundFlowTokenNeeded(Target* target)
 
758
{
 
759
   if(mRequestContext.mProxy.isMyUri(target->uri()))
 
760
   {
 
761
      // .bwc. We don't need to put flow-tokens pointed at ourselves.
 
762
      return false;
 
763
   }
 
764
 
 
765
   if((target->rec().mReceivedFrom.mFlowKey &&
 
766
       target->rec().mUseFlowRouting)
 
767
      || resip::InteropHelper::getRRTokenHackEnabled()
 
768
      || mIsClientBehindNAT)
 
769
   {
 
770
      target->rec().mReceivedFrom.onlyUseExistingConnection=true;
 
771
      return true;
 
772
   }
 
773
 
 
774
   return false;
 
775
}
 
776
 
 
777
bool 
 
778
ResponseContext::needsFlowTokenToWork(const resip::NameAddr& contact) const
 
779
{
 
780
   if(DnsUtil::isIpAddress(contact.uri().host()))
 
781
   {
 
782
      // IP address in host-part.
 
783
      if(contact.uri().scheme()=="sips")
 
784
      {
 
785
         // TLS with no FQDN. Impossible without flow-token fixup, even if no 
 
786
         // NAT is involved.
 
787
         return true;
 
788
      }
 
789
 
 
790
      if(contact.uri().exists(p_transport))
 
791
      {
 
792
         TransportType type = toTransportType(contact.uri().param(p_transport));
 
793
         if(type==TLS || type == DTLS)
 
794
         {
 
795
            // TLS with no FQDN. Impossible without flow-token fixup, even if no 
 
796
            // NAT is involved.
 
797
            return true;
 
798
         }
 
799
      }
 
800
   }
 
801
 
 
802
   if(contact.uri().exists(p_sigcompId))
 
803
   {
 
804
      if(contact.uri().exists(p_transport))
 
805
      {
 
806
         TransportType type = toTransportType(contact.uri().param(p_transport));
 
807
         if(type == TLS || type == TCP)
 
808
         {
 
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.
 
812
            return true;
 
813
         }
 
814
      }
 
815
   }
 
816
   return false;
 
817
}
 
818
 
 
819
bool
 
820
ResponseContext::sendingToSelf(Target* target)
 
821
{
 
822
   if(mRequestContext.mProxy.isMyUri(target->uri()))
 
823
   {
 
824
      return true;
 
825
   }
 
826
   return false;
 
827
}
 
828
 
 
829
void 
 
830
ResponseContext::sendRequest(resip::SipMessage& request)
 
831
{
 
832
   assert (request.isRequest());
 
833
 
 
834
   if (request.method() != CANCEL && 
 
835
       request.method() != ACK)
 
836
   {
 
837
      mRequestContext.getProxy().addClientTransaction(request.getTransactionId(), &mRequestContext);
 
838
      mRequestContext.mTransactionCount++;
 
839
//      if(!mRequestContext.getDigestIdentity().empty())
 
840
//      {
 
841
//         requestPtr->header(h_Identity);
 
842
//         // !bwc! Need to fill in the Identity-Info header telling where our 
 
843
//         // cert can be found.
 
844
//      }
 
845
   }
 
846
 
 
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.
 
856
 
 
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()))
 
865
   {
 
866
      // Look for "id" token
 
867
      bool found = false;
 
868
      PrivacyCategories::iterator it = request.header(h_Privacies).begin();
 
869
      for(; it != request.header(h_Privacies).end() && !found; it++)
 
870
      {
 
871
         std::vector<Data>::iterator itToken = it->value().begin();
 
872
         for(; itToken != it->value().end() && !found; itToken++)
 
873
         {
 
874
            if(*itToken == "id")
 
875
            {
 
876
               request.remove(h_PAssertedIdentities); 
 
877
               found = true;
 
878
            }
 
879
         }
 
880
      }
 
881
   }
 
882
 
 
883
   if (request.method() == ACK)
 
884
   {
 
885
     DebugLog(<<"Posting Ack200DoneMessage");
 
886
     mRequestContext.getProxy().post(new Ack200DoneMessage(mRequestContext.getTransactionId()));
 
887
   }
 
888
 
 
889
   mRequestContext.send(request);
 
890
}
 
891
 
 
892
 
 
893
void
 
894
ResponseContext::processCancel(const SipMessage& request)
 
895
{
 
896
   assert(request.isRequest());
 
897
   assert(request.method() == CANCEL);
 
898
 
 
899
   std::auto_ptr<SipMessage> ok(Helper::makeResponse(request, 200));   
 
900
   mRequestContext.sendResponse(*ok);
 
901
 
 
902
   if (!mRequestContext.mHaveSentFinalResponse)
 
903
   {
 
904
      cancelAllClientTransactions();
 
905
      if(!hasActiveTransactions())
 
906
      {
 
907
         SipMessage reqterm;
 
908
         Helper::makeResponse(reqterm,mRequestContext.getOriginalRequest(),487);
 
909
         mRequestContext.sendResponse(reqterm);
 
910
      }
 
911
   }
 
912
}
 
913
 
 
914
void
 
915
ResponseContext::processTimerC()
 
916
{
 
917
   if (!mRequestContext.mHaveSentFinalResponse)
 
918
   {
 
919
      InfoLog(<<"Canceling client transactions due to timer C.");
 
920
      cancelAllClientTransactions();
 
921
   }
 
922
}
 
923
 
 
924
void
 
925
ResponseContext::processResponse(SipMessage& response)
 
926
{
 
927
   InfoLog (<< "processResponse: " << endl << response);
 
928
 
 
929
   // store this before we pop the via and lose the branch tag
 
930
   mCurrentResponseTid = response.getTransactionId();
 
931
   
 
932
   assert (response.isResponse());
 
933
   assert (response.exists(h_Vias) && !response.header(h_Vias).empty());
 
934
   response.header(h_Vias).pop_front();
 
935
 
 
936
   // Stop processing responses that have nowhere else to go
 
937
   if (response.header(h_Vias).empty())
 
938
   {
 
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
 
943
 
 
944
      if(response.method()==CANCEL)
 
945
      {
 
946
         return;
 
947
      }
 
948
      else if (response.header(h_StatusLine).statusCode() > 199)
 
949
      {
 
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);
 
955
         return;
 
956
      }
 
957
      else if(response.header(h_StatusLine).statusCode() != 100)
 
958
      {
 
959
         InfoLog( << "Received provisional response, but can't forward as there"
 
960
                     " are no more Vias. Ignoring. " << response.brief() );
 
961
         return;
 
962
      }
 
963
   }
 
964
   else // We have a second Via
 
965
   {
 
966
      if(!mRequestContext.getOriginalRequest().getRFC2543TransactionId().empty())
 
967
      {
 
968
         // .bwc. Original request had an RFC 2543 transaction-id. Set in 
 
969
         // response.
 
970
         response.setRFC2543TransactionId(mRequestContext.getOriginalRequest().getRFC2543TransactionId());
 
971
      }
 
972
 
 
973
      const Via& via = response.header(h_Vias).front();
 
974
 
 
975
      if(!via.isWellFormed())
 
976
      {
 
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)
 
982
         {
 
983
            terminateClientTransaction(mCurrentResponseTid);
 
984
         }
 
985
         
 
986
         return;
 
987
      }
 
988
 
 
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);
 
992
 
 
993
      if(!isEqualNoCase(branch,origBranch))
 
994
      {
 
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)
 
1000
         {
 
1001
            terminateClientTransaction(mCurrentResponseTid);
 
1002
         }
 
1003
         
 
1004
         return;
 
1005
      }
 
1006
   }
 
1007
   
 
1008
   DebugLog (<< "Search for " << mCurrentResponseTid << " in " << InserterP(mActiveTransactionMap));
 
1009
 
 
1010
   TransactionMap::iterator i = mActiveTransactionMap.find(mCurrentResponseTid);
 
1011
 
 
1012
   int code = response.header(h_StatusLine).statusCode();
 
1013
   if (i == mActiveTransactionMap.end())
 
1014
   {
 
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)
 
1019
      {
 
1020
         InfoLog( << "Discarding stray response" );
 
1021
      }
 
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!
 
1025
      else
 
1026
      {
 
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);
 
1035
      }
 
1036
      return;
 
1037
   }
 
1038
 
 
1039
   switch (code / 100)
 
1040
   {
 
1041
      case 1:
 
1042
         if(mRequestContext.getOriginalRequest().method()==INVITE)
 
1043
         {
 
1044
            mRequestContext.updateTimerC();
 
1045
         }
 
1046
 
 
1047
         if  (!mRequestContext.mHaveSentFinalResponse)
 
1048
         {
 
1049
            if (code == 100)
 
1050
            {
 
1051
               return;  // stop processing 100 responses
 
1052
            }
 
1053
               
 
1054
            mRequestContext.sendResponse(response);
 
1055
            return;            
 
1056
         }
 
1057
         break;
 
1058
         
 
1059
      case 2:
 
1060
         terminateClientTransaction(mCurrentResponseTid);
 
1061
         if (mRequestContext.getOriginalRequest().method() == INVITE)
 
1062
         {
 
1063
            cancelAllClientTransactions();
 
1064
            mRequestContext.mHaveSentFinalResponse = true;
 
1065
            mBestResponse.header(h_StatusLine).statusCode()=
 
1066
               response.header(h_StatusLine).statusCode();
 
1067
            mRequestContext.sendResponse(response);
 
1068
         }
 
1069
         else if (!mRequestContext.mHaveSentFinalResponse)
 
1070
         {
 
1071
            clearCandidateTransactions();
 
1072
            mRequestContext.mHaveSentFinalResponse = true;
 
1073
            mBestResponse.header(h_StatusLine).statusCode()=
 
1074
               response.header(h_StatusLine).statusCode();
 
1075
 
 
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)))))
 
1084
            {
 
1085
               response.header(h_FlowTimer).value() = InteropHelper::getFlowTimerSeconds();
 
1086
               mRequestContext.getProxy().getStack().enableFlowTimer(mRequestContext.getOriginalRequest().getSource());
 
1087
            }
 
1088
 
 
1089
            mRequestContext.sendResponse(response);            
 
1090
         }
 
1091
         break;
 
1092
         
 
1093
      case 3:
 
1094
      case 4:
 
1095
      case 5:
 
1096
         DebugLog (<< "forwardedFinal=" << mRequestContext.mHaveSentFinalResponse 
 
1097
                   << " outstanding client transactions: " << InserterP(mActiveTransactionMap));
 
1098
         terminateClientTransaction(mCurrentResponseTid);
 
1099
         if (!mRequestContext.mHaveSentFinalResponse)
 
1100
         {
 
1101
            int priority = getPriority(response);
 
1102
            if (priority == mBestPriority)
 
1103
            {
 
1104
               if (code == 401 || code == 407)
 
1105
               {
 
1106
                  if (response.exists(h_WWWAuthenticates))
 
1107
                  {
 
1108
                     for ( Auths::iterator i=response.header(h_WWWAuthenticates).begin(); 
 
1109
                           i != response.header(h_WWWAuthenticates).end() ; ++i)
 
1110
                     {                     
 
1111
                        mBestResponse.header(h_WWWAuthenticates).push_back(*i);
 
1112
                     }
 
1113
                  }
 
1114
                  
 
1115
                  if (response.exists(h_ProxyAuthenticates))
 
1116
                  {
 
1117
                     for ( Auths::iterator i=response.header(h_ProxyAuthenticates).begin(); 
 
1118
                           i != response.header(h_ProxyAuthenticates).end() ; ++i)
 
1119
                     {                     
 
1120
                        mBestResponse.header(h_ProxyAuthenticates).push_back(*i);
 
1121
                     }
 
1122
                     mBestResponse.header(h_StatusLine).statusCode() = 407;
 
1123
                  }
 
1124
               }
 
1125
               else if (code / 100 == 3) // merge 3xx
 
1126
               {
 
1127
 
 
1128
                  if(mBestResponse.header(h_StatusLine).statusCode()/100!=3)
 
1129
                  {
 
1130
                     // .bwc. Do not merge contacts in 3xx with contacts from a
 
1131
                     // previous 4xx or 5xx
 
1132
                     mBestResponse.header(h_Contacts).clear();
 
1133
                  }
 
1134
 
 
1135
                  for (NameAddrs::iterator i=response.header(h_Contacts).begin(); 
 
1136
                       i != response.header(h_Contacts).end(); ++i)
 
1137
                  {
 
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.
 
1143
 
 
1144
                     if(!i->isWellFormed() || i->isAllContacts())
 
1145
                     {
 
1146
                        // .bwc. Garbage contact; ignore it.
 
1147
                        continue;
 
1148
                     }
 
1149
                     
 
1150
                     mBestResponse.header(h_Contacts).push_back(*i);
 
1151
                  }
 
1152
 
 
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;
 
1157
               }
 
1158
            }
 
1159
            else if (priority < mBestPriority)
 
1160
            {
 
1161
               mBestPriority = priority;
 
1162
               mBestResponse = response;
 
1163
            }
 
1164
            
 
1165
            if (areAllTransactionsTerminated())
 
1166
            {
 
1167
               forwardBestResponse();
 
1168
            }
 
1169
         }
 
1170
         break;
 
1171
         
 
1172
      case 6:
 
1173
         terminateClientTransaction(mCurrentResponseTid);
 
1174
         if (!mRequestContext.mHaveSentFinalResponse)
 
1175
         {
 
1176
            if (mBestResponse.header(h_StatusLine).statusCode() / 100 != 6)
 
1177
            {
 
1178
               mBestResponse = response;
 
1179
               mBestPriority=0; //6xx class responses take precedence over all 3xx,4xx, and 5xx
 
1180
               if (mRequestContext.getOriginalRequest().method() == INVITE)
 
1181
               {
 
1182
                  // CANCEL INVITE branches
 
1183
                  cancelAllClientTransactions();
 
1184
               }
 
1185
            }
 
1186
            
 
1187
            if (areAllTransactionsTerminated())
 
1188
            {
 
1189
               forwardBestResponse();
 
1190
            }
 
1191
         }
 
1192
         break;
 
1193
         
 
1194
      default:
 
1195
         assert(0);
 
1196
         break;
 
1197
   }
 
1198
}
 
1199
 
 
1200
void
 
1201
ResponseContext::cancelClientTransaction(repro::Target* target)
 
1202
{
 
1203
   if (target->status() == Target::Started)
 
1204
   {
 
1205
      InfoLog (<< "Cancel client transaction: " << target);
 
1206
      mRequestContext.cancelClientTransaction(target->via().param(p_branch).getTransactionId());
 
1207
 
 
1208
      DebugLog(<< "Canceling a transaction with uri: " 
 
1209
               << resip::Data::from(target->uri()) << " , to host: " 
 
1210
               << target->via().sentHost());
 
1211
      target->status() = Target::Cancelled;
 
1212
   }
 
1213
   else if (target->status() == Target::Candidate)
 
1214
   {
 
1215
      target->status() = Target::Terminated;
 
1216
   }
 
1217
}
 
1218
 
 
1219
void 
 
1220
ResponseContext::terminateClientTransaction(const resip::Data& tid)
 
1221
{
 
1222
 
 
1223
   InfoLog (<< "Terminating client transaction: " << tid << " all = " << areAllTransactionsTerminated());
 
1224
 
 
1225
   TransactionMap::iterator i = mActiveTransactionMap.find(tid);
 
1226
   if(i != mActiveTransactionMap.end())
 
1227
   {
 
1228
      InfoLog (<< "client transactions: " << InserterP(mActiveTransactionMap));
 
1229
      i->second->status() = Target::Terminated;
 
1230
      mTerminatedTransactionMap[tid] = i->second;
 
1231
      mActiveTransactionMap.erase(i);
 
1232
      return;
 
1233
   }
 
1234
   
 
1235
   TransactionMap::iterator j = mCandidateTransactionMap.find(tid);
 
1236
   if(j != mCandidateTransactionMap.end())
 
1237
   {
 
1238
      InfoLog (<< "client transactions: " << InserterP(mCandidateTransactionMap));
 
1239
      j->second->status() = Target::Terminated;
 
1240
      mTerminatedTransactionMap[tid] = j->second;
 
1241
      mCandidateTransactionMap.erase(j);
 
1242
      return;   
 
1243
   }
 
1244
      
 
1245
}
 
1246
 
 
1247
 
 
1248
int
 
1249
ResponseContext::getPriority(const resip::SipMessage& msg)
 
1250
{
 
1251
   int responseCode = msg.header(h_StatusLine).statusCode();
 
1252
   int p = 0;  // "p" is the relative priority of the response
 
1253
 
 
1254
      assert(responseCode >= 300 && responseCode <= 599);
 
1255
      if (responseCode <= 399)  // 3xx response
 
1256
      { 
 
1257
         return 5;  // response priority is 5
 
1258
      }
 
1259
      if (responseCode >= 500)
 
1260
      {
 
1261
         switch(responseCode)
 
1262
         {
 
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)
 
1266
            case 513:
 
1267
                  break;
 
1268
            default:
 
1269
                  return 42; // response priority of other 5xx is 42
 
1270
         }
 
1271
      }
 
1272
 
 
1273
      switch(responseCode)
 
1274
      {
 
1275
         // Easy to Repair Responses: 412, 484, 422, 423, 407, 401, 300..399, 402
 
1276
         case 412:              // Publish ETag was stale
 
1277
            return 1;
 
1278
         case 484:              // overlap dialing
 
1279
            return 2;
 
1280
         case 422:              // Session-Timer duration too long
 
1281
         case 423:              // Expires too short
 
1282
            return 3;
 
1283
         case 407:              // Proxy-Auth
 
1284
         case 401:              // UA Digest challenge
 
1285
            return 4;
 
1286
                  
 
1287
         // 3xx responses have p = 5
 
1288
         case 402:              // Payment required
 
1289
            return 6;
 
1290
 
 
1291
         // Responses used for negotiation: 493, 429, 420, 406, 415, 488
 
1292
         case 493:              // Undecipherable, try again unencrypted 
 
1293
            return 10;
 
1294
 
 
1295
         case 420:              // Required Extension not supported, try again without
 
1296
            return 12;
 
1297
 
 
1298
         case 406:              // Not Acceptable
 
1299
         case 415:              // Unsupported Media Type
 
1300
         case 488:              // Not Acceptable Here
 
1301
            return 13;
 
1302
                  
 
1303
         // Possibly useful for negotiation, but less likely: 421, 416, 417, 494, 580, 485, 405, 501, 413, 414
 
1304
         
 
1305
         case 416:              // Unsupported scheme
 
1306
         case 417:              // Unknown Resource-Priority
 
1307
            return 20;
 
1308
 
 
1309
         case 405:              // Method not allowed (both used for negotiating REFER, PUBLISH, etc..
 
1310
         case 501:              // Usually used when the method is not OK
 
1311
            return 21;
 
1312
 
 
1313
         case 580:              // Preconditions failure
 
1314
            return 22;
 
1315
 
 
1316
         case 485:              // Ambiguous userpart.  A bit better than 404?
 
1317
            return 23;
 
1318
 
 
1319
         case 428:              // Use Identity header
 
1320
         case 429:              // Provide Referrer Identity 
 
1321
         case 494:              // Use the sec-agree mechanism
 
1322
            return 24;
 
1323
 
 
1324
         case 413:              // Request too big
 
1325
         case 414:              // URI too big
 
1326
            return 25;
 
1327
 
 
1328
         case 421:              // An extension required by the server was not in the Supported header
 
1329
            return 26;
 
1330
         
 
1331
         // The request isn't repairable, but at least we can try to provide some 
 
1332
         // useful information: 486, 480, 410, 404, 403, 487
 
1333
         
 
1334
         case 486:              // Busy Here
 
1335
            return 30;
 
1336
 
 
1337
         case 480:              // Temporarily unavailable
 
1338
            return 31;
 
1339
 
 
1340
         case 410:              // Gone
 
1341
            return 32;
 
1342
 
 
1343
         case 436:              // Bad Identity-Info 
 
1344
         case 437:              // Unsupported Certificate
 
1345
         case 513:      // Message too large
 
1346
            return 33;
 
1347
 
 
1348
         case 403:              // Forbidden
 
1349
            return 34;
 
1350
 
 
1351
         case 404:              // Not Found
 
1352
            return 35;
 
1353
 
 
1354
         case 487:              // Some branches were cancelled, if the UAC sent a CANCEL this is good news
 
1355
            return 36;
 
1356
 
 
1357
         // We are hosed: 503, 483, 482, 481, other 5xx, 400, 491, 408  // totally useless
 
1358
 
 
1359
         case 503:      // bad news, we should never forward this back anyway
 
1360
            return 43;
 
1361
 
 
1362
         case 483:      // loops, encountered
 
1363
         case 482:
 
1364
            return 41;
 
1365
                  
 
1366
         // other 5xx   p = 42
 
1367
 
 
1368
         // UAS is seriously confused: p = 43
 
1369
         // case 481:   
 
1370
         // case 400:
 
1371
         // case 491:
 
1372
         // default:
 
1373
         
 
1374
         case 408:      // very, very bad  (even worse than the remaining 4xx responses)
 
1375
            return 49;
 
1376
         
 
1377
         default:
 
1378
            return 43;
 
1379
      }
 
1380
   return p;
 
1381
}
 
1382
 
 
1383
bool 
 
1384
ResponseContext::CompareStatus::operator()(const resip::SipMessage& lhs, const resip::SipMessage& rhs) const
 
1385
{
 
1386
   assert(lhs.isResponse());
 
1387
   assert(rhs.isResponse());
 
1388
   
 
1389
   // !rwm! replace with correct thingy here
 
1390
   return lhs.header(h_StatusLine).statusCode() < rhs.header(h_StatusLine).statusCode();
 
1391
}
 
1392
 
 
1393
void
 
1394
ResponseContext::forwardBestResponse()
 
1395
{
 
1396
   InfoLog (<< "Forwarding best response: " << mBestResponse.brief());
 
1397
   
 
1398
   clearCandidateTransactions();
 
1399
   
 
1400
   if(mRequestContext.getOriginalRequest().method()==INVITE)
 
1401
   {
 
1402
      cancelActiveClientTransactions();
 
1403
   }
 
1404
   
 
1405
   if(mBestResponse.header(h_StatusLine).statusCode() == 503)
 
1406
   {
 
1407
      //See RFC 3261 sec 16.7, page 110, paragraph 2
 
1408
      mBestResponse.header(h_StatusLine).statusCode() = 480;
 
1409
   }
 
1410
 
 
1411
   if(mBestResponse.header(h_StatusLine).statusCode() == 408 &&
 
1412
      mBestResponse.method()!=INVITE)
 
1413
   {
 
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
 
1418
   }
 
1419
   else
 
1420
   {
 
1421
      mRequestContext.sendResponse(mBestResponse);
 
1422
   }
 
1423
}
 
1424
 
 
1425
EncodeStream&
 
1426
repro::operator<<(EncodeStream& strm, const ResponseContext& rc)
 
1427
{
 
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);
 
1435
 
 
1436
   return strm;
 
1437
}
 
1438
 
 
1439
 
 
1440
/* ====================================================================
 
1441
 * The Vovida Software License, Version 1.0 
 
1442
 * 
 
1443
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
 
1444
 * 
 
1445
 * Redistribution and use in source and binary forms, with or without
 
1446
 * modification, are permitted provided that the following conditions
 
1447
 * are met:
 
1448
 * 
 
1449
 * 1. Redistributions of source code must retain the above copyright
 
1450
 *    notice, this list of conditions and the following disclaimer.
 
1451
 * 
 
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
 
1455
 *    distribution.
 
1456
 * 
 
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.
 
1462
 *
 
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.
 
1466
 * 
 
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
 
1479
 * DAMAGE.
 
1480
 * 
 
1481
 * ====================================================================
 
1482
 * 
 
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/>.
 
1487
 *
 
1488
 */