< Previous by Date Date Index Next by Date >
  Thread Index Next in Thread >

[reSIProcate] DnsResult blacklistLast,greylistLast question.


Dear resiprocate devels,
resiprocate version 1.8.8

I use proxy,built above resip stack. In particular, there are a fiew intermediate proxy servers: N1,N2,N3.

I've met next issue:
1) there is an active session.
2) some client starts one more session,sending malformed sip message to proxy1, proxy1 retransmits that message to Proxy2 and proxy2 responds with 500 Server internal error. Proxy1 tries to retransmit that message several times and after the last one it penalizes given transport by black listing. 3) At the same time session from item1 has not been finished yet. If any participant from session1 will send any sip message - TransportSelector will generate TransportFailure or TCP transport will be selected if it is configured - as result session1 becomes broken/hung.

I think UAC penalization - is good idea,but proxy penalization leads to undefined behaviour.

Considering this I  would like to ask a few questions,if you don't mind:
1) Is it possible to add some exception list to DnsResult::blackListLast/DnsResult::greyListLast stuff? 2) Could you please take a look on provided patch,which provides some kind of solution?

Appreciate in advance.
diff --git resip/stack/DnsResult.cxx resip/stack/DnsResult.cxx
index cb4b8ee..54d7e57 100644
--- resip/stack/DnsResult.cxx
+++ resip/stack/DnsResult.cxx
@@ -92,7 +92,7 @@ EnumResult::onDnsResult(const DNSResult<DnsCnameRecord>&)
    delete this;
 }
 
-DnsResult::DnsResult(DnsInterface& interfaceObj, DnsStub& dns, RRVip& vip, DnsHandler* handler) 
+DnsResult::DnsResult(DnsInterface& interfaceObj, DnsStub& dns, RRVip& vip, DnsHandler* handler)
    : mInterface(interfaceObj),
      mDns(dns),
      mVip(vip),
@@ -115,15 +115,15 @@ DnsResult::~DnsResult()
    assert(mType != Pending);
 }
 
-void 
+void
 DnsResult::transition(Type t)
 {
-   if((t == Pending || t== Available) && 
+   if((t == Pending || t== Available) &&
          (mType== Finished || mType == Destroyed) )
    {
       assert(0);
    }
-   
+
    mType = t;
 }
 
@@ -132,7 +132,7 @@ DnsResult::destroy()
 {
    assert(this);
    //DebugLog (<< "DnsResult::destroy() " << *this);
-   
+
    if (mType == Pending)
    {
       transition(Destroyed);
@@ -152,14 +152,20 @@ DnsResult::blacklistLast(UInt64 expiry)
       assert(!mLastReturnedPath.empty());
       assert(mLastReturnedPath.size()<=3);
       Item top = mLastReturnedPath.back();
-   
+
+      if( mHandler->isBlackListException( mLastResult ) )
+      {
+        WarningLog( << mLastResult << " is penalization exception" );
+        return false;
+      }
+
       mInterface.getMarkManager().mark(mLastResult,expiry,TupleMarkManager::BLACK);
-   
+
       DebugLog( << "Remove vip " << top.domain << "(" << top.rrType << ")");
       mVip.removeVip(top.domain, top.rrType);
       return true;
    }
-   
+
    return false;
 }
 
@@ -171,14 +177,20 @@ DnsResult::greylistLast(UInt64 expiry)
       assert(!mLastReturnedPath.empty());
       assert(mLastReturnedPath.size()<=3);
       Item top = mLastReturnedPath.back();
-   
+
+      if( mHandler->isBlackListException( mLastResult ) )
+      {
+        WarningLog( << mLastResult << " is penalization exception" );
+        return false;
+      }
+
       mInterface.getMarkManager().mark(mLastResult,expiry,TupleMarkManager::GREY);
-   
+
       DebugLog( << "Remove vip " << top.domain << "(" << top.rrType << ")");
       mVip.removeVip(top.domain, top.rrType);
       return true;
    }
-   
+
    return false;
 }
 
@@ -209,22 +221,22 @@ DnsResult::next()
 {
    assert(available()==Available);
    assert(mCurrentPath.size()<=3);
-   
+
    mLastResult=mResults.front();
    mResults.pop_front();
-   
-   if(!mCurrentPath.empty() && 
+
+   if(!mCurrentPath.empty() &&
       (mCurrentPath.back().rrType==T_A || mCurrentPath.back().rrType==T_AAAA))
    {
       mCurrentPath.pop_back();
    }
-   
+
    Item AorAAAA;
    AorAAAA.domain = mLastResult.getTargetDomain();
    AorAAAA.rrType = mLastResult.isV4() ? T_A : T_AAAA;
    AorAAAA.value = Tuple::inet_ntop(mLastResult);
    mCurrentPath.push_back(AorAAAA);
-   
+
    StackLog (<< "Returning next dns entry: " << mLastResult);
    mLastReturnedPath=mCurrentPath;
    mHaveReturnedResults=true;
@@ -263,7 +275,7 @@ DnsResult::lookup(const Uri& uri, const std::vector<Data> &enumSuffixes,
          {
             InfoLog (<< "Doing ENUM lookup on " << *it);
             mDns.lookup<RR_NAPTR>(*it, Protocol::Enum,
-               new EnumResult(*this, order++)); 
+               new EnumResult(*this, order++));
          }
          return;
       }
@@ -276,7 +288,7 @@ DnsResult::lookup(const Uri& uri, const std::vector<Data> &enumSuffixes,
 void
 DnsResult::lookupInternal(const Uri& uri)
 {
-   //assert(uri.scheme() == Symbols::Sips || uri.scheme() == Symbols::Sip);  
+   //assert(uri.scheme() == Symbols::Sips || uri.scheme() == Symbols::Sip);
    mSips = (uri.scheme() == Symbols::Sips);
    mTarget = (!mSips && uri.exists(p_maddr)) ? uri.param(p_maddr) : uri.host();
    mSrvKey = Symbols::UNDERSCORE + uri.scheme().substr(0, uri.scheme().size()) + Symbols::DOT;
@@ -286,7 +298,7 @@ DnsResult::lookupInternal(const Uri& uri)
    {
       mTransport = Tuple::toTransport(uri.param(p_transport));
       mHaveChosenTransport=true;
-      
+
       if (isNumeric) // IP address specified
       {
          mPort = getDefaultPort(mTransport, uri.port());
@@ -312,8 +324,8 @@ DnsResult::lookupInternal(const Uri& uri)
          mPort = uri.port();
          lookupHost(mTarget); // for current target and port
       }
-      else 
-      { 
+      else
+      {
          if (mSips)
          {
             if (mTransport == UDP)
@@ -325,7 +337,7 @@ DnsResult::lookupInternal(const Uri& uri)
                   if (mHandler) mHandler->handle(this);
                   return;
                }
-               if(!mDns.supportedType(T_SRV)) 
+               if(!mDns.supportedType(T_SRV))
                {
                   mPort = getDefaultPort(mTransport, uri.port());
                   lookupHost(mTarget); // for current target and port
@@ -347,7 +359,7 @@ DnsResult::lookupInternal(const Uri& uri)
                   if (mHandler) mHandler->handle(this);
                   return;
                }
-               if(!mDns.supportedType(T_SRV)) 
+               if(!mDns.supportedType(T_SRV))
                {
                   mPort = getDefaultPort(mTransport, uri.port());
                   lookupHost(mTarget); // for current target and port
@@ -369,7 +381,7 @@ DnsResult::lookupInternal(const Uri& uri)
                return;
             }
 
-            if(!mDns.supportedType(T_SRV)) 
+            if(!mDns.supportedType(T_SRV))
             {
                mPort = getDefaultPort(mTransport, uri.port());
                lookupHost(mTarget); // for current target and port
@@ -411,7 +423,7 @@ DnsResult::lookupInternal(const Uri& uri)
       {
          TupleMarkManager::MarkType mark=TupleMarkManager::BLACK;
          Tuple tuple;
-         
+
          if(isNumeric)
          {
             if(mSips)
@@ -435,7 +447,7 @@ DnsResult::lookupInternal(const Uri& uri)
                   tuple=Tuple(mTarget,mPort,mTransport,mTarget);
                   mark=mInterface.getMarkManager().getMarkType(tuple);
                }
-               
+
                if(mark!=TupleMarkManager::OK && (mInterface.isSupported(TCP, V4) ||
                                     mInterface.isSupported(TCP, V6)))
                {
@@ -444,7 +456,7 @@ DnsResult::lookupInternal(const Uri& uri)
                   tuple=Tuple(mTarget,mPort,mTransport,mTarget);
                   mark=mInterface.getMarkManager().getMarkType(tuple);
                }
-               
+
                if(mark!=TupleMarkManager::OK && (mInterface.isSupported(TLS, V4) ||
                                     mInterface.isSupported(TLS, V6)))
                {
@@ -454,7 +466,7 @@ DnsResult::lookupInternal(const Uri& uri)
                   mark=mInterface.getMarkManager().getMarkType(tuple);
                }
             }
-            
+
             if(mark==TupleMarkManager::OK || mark==TupleMarkManager::GREY)
             {
                mHaveChosenTransport=true;
@@ -469,14 +481,14 @@ DnsResult::lookupInternal(const Uri& uri)
                transition(Available);
                DebugLog(<< "Numeric result, but this result is currently blacklisted: " << tuple);
             }
-            
+
             if (mHandler) mHandler->handle(this);
 
          }
          else // host is not numeric, so we need to make a query
          {
             mTransport=UNKNOWN_TRANSPORT;
-            
+
             if(mSips)
             {
                if(mInterface.isSupported(TLS, V4) || mInterface.isSupported(TLS, V6))
@@ -496,7 +508,7 @@ DnsResult::lookupInternal(const Uri& uri)
             {
                mTransport=TLS;
             }
-            
+
             if(mTransport!=UNKNOWN_TRANSPORT)
             {
                mPort=getDefaultPort(mTransport,uri.port());
@@ -562,7 +574,7 @@ DnsResult::getDefaultPort(TransportType transport, int port)
             return Symbols::SipWssPort;
          default:
             ErrLog( << "Should not get this - unknown transport" );
-            return Symbols::DefaultSipPort; // !cj! todo - remove 
+            return Symbols::DefaultSipPort; // !cj! todo - remove
             assert(0);
       }
    }
@@ -638,7 +650,7 @@ DnsResult::primeResults()
 }
 
 // implement the selection algorithm from rfc2782 (SRV records)
-DnsResult::SRV 
+DnsResult::SRV
 DnsResult::retrieveSRV()
 {
     // !ah! if mTransport is known -- should we ignore those that don't match?!
@@ -648,7 +660,7 @@ DnsResult::retrieveSRV()
    const SRV& srv = *mSRVResults.begin();
    int priority = srv.priority;
    TransportType transport=UNKNOWN_TRANSPORT;
-   
+
    if(!mHaveChosenTransport)
    {
       // .bwc. We have not chosen a transport yet; this happens when we fail
@@ -661,24 +673,24 @@ DnsResult::retrieveSRV()
    else
    {
       // .bwc. We chose our transport before we started looking up SRVs.
-      // All SRVs must match. 
-      
+      // All SRVs must match.
+
       transport=mTransport;
       assert(mSRVResults.begin()->transport==transport);
    }
-   
+
    if (mCumulativeWeight == 0)
    {
-      for (std::vector<SRV>::iterator i=mSRVResults.begin(); 
-           i!=mSRVResults.end() 
-              && i->priority == priority 
+      for (std::vector<SRV>::iterator i=mSRVResults.begin();
+           i!=mSRVResults.end()
+              && i->priority == priority
               && i->transport == transport; i++)
       {
          assert(i->weight>=0);
          mCumulativeWeight += i->weight;
       }
    }
-   
+
    int selected =0;
    if(mCumulativeWeight!=0)
    {
@@ -687,13 +699,13 @@ DnsResult::retrieveSRV()
    else
    {
       // .bwc. All of the remaining SRVs (at this priority/type) have a weight
-      // of 0. The best we can do here is pick arbitrarily. In this case, we 
+      // of 0. The best we can do here is pick arbitrarily. In this case, we
       // will end up picking the first.
       // (selected will be less than the weight of the first SRV, causing the
       // loop below to break on the first iteration)
       selected=-1;
    }
-   
+
    StackLog (<< "cumulative weight = " << mCumulativeWeight << " selected=" << selected);
 
    std::vector<SRV>::iterator i;
@@ -706,7 +718,7 @@ DnsResult::retrieveSRV()
          break;
       }
    }
-   
+
    if (i == mSRVResults.end())
    {
       InfoLog (<< "SRV Results problem selected=" << selected << " cum=" << mCumulativeWeight);
@@ -715,12 +727,12 @@ DnsResult::retrieveSRV()
    SRV next = *i;
    mCumulativeWeight -= next.weight;
    mSRVResults.erase(i);
-   
+
    if(!mSRVResults.empty())
    {
       int nextPriority=mSRVResults.begin()->priority;
       TransportType nextTransport=mSRVResults.begin()->transport;
-      
+
       // .bwc. If we have finished traversing a priority value/transport type,
       // we reset the cumulative weight to 0, to prompt its recalculation.
       if(priority!=nextPriority || transport!=nextTransport)
@@ -728,7 +740,7 @@ DnsResult::retrieveSRV()
          mCumulativeWeight=0;
       }
    }
-   
+
    StackLog (<< "SRV: " << Inserter(mSRVResults));
 
    return next;
@@ -738,7 +750,7 @@ DnsResult::NAPTR::NAPTR() : order(0), pref(0)
 {
 }
 
-bool 
+bool
 DnsResult::NAPTR::operator<(const DnsResult::NAPTR& rhs) const
 {
    if (key.empty()) // default value
@@ -772,7 +784,7 @@ DnsResult::SRV::SRV() : priority(0), weight(0), port(0)
     // .kw. member "transport" is not initialized. good default?
 }
 
-bool 
+bool
 DnsResult::SRV::operator<(const DnsResult::SRV& rhs) const
 {
    if (naptrpref < rhs.naptrpref)
@@ -818,7 +830,7 @@ void DnsResult::onDnsResult(const DNSResult<DnsHostRecord>& result)
    }
    StackLog (<< "Received dns result for: " << mTarget);
    StackLog (<< "DnsResult::onDnsResult() " << result.status);
-   
+
    // This function assumes that the A query that caused this callback
    // is the _only_ outstanding DNS query that might result in a
    // callback into this function
@@ -835,7 +847,7 @@ void DnsResult::onDnsResult(const DNSResult<DnsHostRecord>& result)
          in_addr addr;
          addr.s_addr = (*it).addr().s_addr;
          Tuple tuple(addr, mPort, mTransport, mTarget);
-         
+
          switch(mInterface.getMarkManager().getMarkType(tuple))
          {
             case TupleMarkManager::OK:
@@ -850,9 +862,9 @@ void DnsResult::onDnsResult(const DNSResult<DnsHostRecord>& result)
             default:
                ;// .bwc. Do nothing.
          }
-      
+
       }
-      
+
    }
    else
    {
@@ -895,7 +907,7 @@ void DnsResult::onDnsResult(const DNSResult<DnsHostRecord>& result)
                    {
                       SOCKADDR_IN *pSockAddrIn = (SOCKADDR_IN *)pQueryResult->lpcsaBuffer[i].RemoteAddr.lpSockaddr;
                       Tuple tuple(pSockAddrIn->sin_addr, mPort, mTransport, mTarget);
-                      
+
                       if(mInterface.getMarkManager().getMarkType(tuple)!=TupleMarkManager::BLACK)
                       {
                         // .bwc. This is the only result we have, so it doesn't
@@ -904,14 +916,14 @@ void DnsResult::onDnsResult(const DNSResult<DnsHostRecord>& result)
                         mResults.push_back(tuple);
                         transition(Available);
                       }
-                   
+
                    }
                 }
              }
              delete [] pQueryResult;
              WSALookupServiceEnd(hQuery);
          }
-         
+
          if(mResults.empty())
          {
             if(mSRVResults.empty())
@@ -961,7 +973,7 @@ void DnsResult::onDnsResult(const DNSResult<DnsHostRecord>& result)
          }
 #endif
       }
-      else 
+      else
       {
          transition(Available);
       }
@@ -994,7 +1006,7 @@ void DnsResult::onDnsResult(const DNSResult<DnsAAAARecord>& result)
       for (vector<DnsAAAARecord>::const_iterator it = result.records.begin(); it != result.records.end(); ++it)
       {
          Tuple tuple((*it).v6Address(), mPort, mTransport, mTarget);
-         
+
          switch(mInterface.getMarkManager().getMarkType(tuple))
          {
             case TupleMarkManager::OK:
@@ -1009,9 +1021,9 @@ void DnsResult::onDnsResult(const DNSResult<DnsAAAARecord>& result)
             default:
                ;// .bwc. Do nothing.
          }
-      
+
       }
-      
+
    }
    else
    {
@@ -1089,10 +1101,10 @@ void DnsResult::onDnsResult(const DNSResult<DnsSrvRecord>& result)
             StackLog (<< "Skipping SRV " << srv.key);
             continue;
          }
-         
+
          if(!mHaveChosenTransport || srv.transport==mTransport)
          {
-            // .bwc. If we have not committed to a given transport, or we have 
+            // .bwc. If we have not committed to a given transport, or we have
             // committed to a given transport which this SRV matches, we will
             // add this SRV. We do not add SRVs that do not match a transport
             // we have committed to.
@@ -1105,8 +1117,8 @@ void DnsResult::onDnsResult(const DNSResult<DnsSrvRecord>& result)
       StackLog (<< "SRV lookup failed: " << result.domain << " " << result.status);
    }
 
-   // no outstanding queries 
-   if (mSRVCount == 0) 
+   // no outstanding queries
+   if (mSRVCount == 0)
    {
       if (mSRVResults.empty())
       {
@@ -1147,7 +1159,7 @@ void DnsResult::onDnsResult(const DNSResult<DnsSrvRecord>& result)
          {
             mPort = getDefaultPort(mTransport, 0);
          }
-         
+
          StackLog (<< "No SRV records for " << mTarget << ". Trying A records");
          if (mInterface.isSupported(mTransport, V6) || mInterface.isSupported(mTransport, V4))
          {
@@ -1177,7 +1189,7 @@ DnsResult::onEnumResult(const DNSResult<DnsNaptrRecord>& result, int order)
    mDoingEnum--;
 
    StackLog(<< "checking result of ENUM query, remaining queries outstanding = " << mDoingEnum);
-   
+
    if (result.status == 0)
    {
       DnsNaptrRecord best;
@@ -1187,7 +1199,7 @@ DnsResult::onEnumResult(const DNSResult<DnsNaptrRecord>& result, int order)
       {
          InfoLog (<< "service=" << i->service()
                   << " order=" << i->order()
-                  << " flags="  << i->flags() 
+                  << " flags="  << i->flags()
                   << " regexp substitution=" << i->regexp().replacement()
                   << " replacement=" << i->replacement());
 
@@ -1195,7 +1207,7 @@ DnsResult::onEnumResult(const DNSResult<DnsNaptrRecord>& result, int order)
                isEqualNoCase(i->service(), enumService2) )  && // only E2U records
               //i->flags().find("u") != Data::npos && // must be terminal record
               i->replacement().empty() )
-               
+
          {
             if (best.order() == -1)
             {
@@ -1205,14 +1217,14 @@ DnsResult::onEnumResult(const DNSResult<DnsNaptrRecord>& result, int order)
             {
                best = *i;
             }
-            else if (i->order() == best.order() && 
+            else if (i->order() == best.order() &&
                      i->preference() < best.preference())
             {
                best = *i;
             }
          }
       }
-      
+
       if (best.order() != -1)
       {
          InfoLog (<< "Found an enum result: " << best.regexp().replacement());
@@ -1268,23 +1280,23 @@ DnsResult::onNaptrResult(const DNSResult<DnsNaptrRecord>& result)
          naptr.regex = (*it).regexp();
          naptr.replacement = (*it).replacement();
          naptr.service = (*it).service();
-         
+
          StackLog (<< "Received NAPTR record: " << naptr);
-         
+
          if ( !mSips || naptr.service.find("SIPS") == 0)
          {
             if (mInterface.isSupported(naptr.service))
             {
                supportedNAPTRs.push_back(naptr);
                if(naptr.order < preferredNAPTROrder)
-               {               
+               {
                   preferredNAPTROrder = naptr.order;
                }
             }
          }
       }
 
-      // This means that dns / NAPTR is misconfigured for this client 
+      // This means that dns / NAPTR is misconfigured for this client
       if (supportedNAPTRs.empty())
       {
          StackLog (<< "There are no NAPTR records supported by this client so do an SRV lookup instead");
@@ -1365,7 +1377,7 @@ DnsResult::onNaptrResult(const DNSResult<DnsNaptrRecord>& result)
    }
 }
 
-void 
+void
 DnsResult::onDnsResult(const DNSResult<DnsNaptrRecord>& result)
 {
    StackLog (<< "Received NAPTR result for: " << mInputUri << " target=" << mTarget);
@@ -1381,7 +1393,7 @@ DnsResult::onDnsResult(const DNSResult<DnsNaptrRecord>& result)
    }
 
    onNaptrResult(result);
-  
+
 }
 
 void DnsResult::onDnsResult(const DNSResult<DnsCnameRecord>& result)
@@ -1396,7 +1408,7 @@ void DnsResult::clearCurrPath()
    }
 }
 
-EncodeStream& 
+EncodeStream&
 resip::operator<<(EncodeStream& strm, const resip::DnsResult& result)
 {
    strm << result.mTarget << " --> " << Inserter(result.mResults);
@@ -1404,7 +1416,7 @@ resip::operator<<(EncodeStream& strm, const resip::DnsResult& result)
 }
 
 
-EncodeStream& 
+EncodeStream&
 resip::operator<<(EncodeStream& strm, const resip::DnsResult::NAPTR& naptr)
 {
    strm << "key=" << naptr.key
@@ -1417,11 +1429,11 @@ resip::operator<<(EncodeStream& strm, const resip::DnsResult::NAPTR& naptr)
    return strm;
 }
 
-EncodeStream& 
+EncodeStream&
 resip::operator<<(EncodeStream& strm, const resip::DnsResult::SRV& srv)
 {
    strm << "key=" << srv.key
-        << " t=" << Tuple::toData(srv.transport) 
+        << " t=" << Tuple::toData(srv.transport)
         << " p=" << srv.priority
         << " w=" << srv.weight
         << " port=" << srv.port
@@ -1429,24 +1441,24 @@ resip::operator<<(EncodeStream& strm, const resip::DnsResult::SRV& srv)
    return strm;
 }
 
-//  Copyright (c) 2003, Jason Fischl 
+//  Copyright (c) 2003, Jason Fischl
 /* ====================================================================
- * The Vovida Software License, Version 1.0 
- * 
+ * The Vovida Software License, Version 1.0
+ *
  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 
+ *
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
- * 
+ *
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in
  *    the documentation and/or other materials provided with the
  *    distribution.
- * 
+ *
  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
  *    and "Vovida Open Communication Application Library (VOCAL)" must
  *    not be used to endorse or promote products derived from this
@@ -1456,7 +1468,7 @@ resip::operator<<(EncodeStream& strm, const resip::DnsResult::SRV& srv)
  * 4. Products derived from this software may not be called "VOCAL", nor
  *    may "VOCAL" appear in their name, without prior written
  *    permission of Vovida Networks, Inc.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
@@ -1470,9 +1482,9 @@ resip::operator<<(EncodeStream& strm, const resip::DnsResult::SRV& srv)
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  * DAMAGE.
- * 
+ *
  * ====================================================================
- * 
+ *
  * This software consists of voluntary contributions made by Vovida
  * Networks, Inc. and many individuals on behalf of Vovida Networks,
  * Inc.  For more information on Vovida Networks, Inc., please see
diff --git resip/stack/TransactionState.cxx resip/stack/TransactionState.cxx
index 0efe067..7210780 100644
--- resip/stack/TransactionState.cxx
+++ resip/stack/TransactionState.cxx
@@ -45,13 +45,13 @@ using namespace resip;
 
 UInt32 TransactionState::StatelessIdCounter = 0;
 
-TransactionState::TransactionState(TransactionController& controller, Machine m, 
-                                   State s, const Data& id, MethodTypes method, const Data& methodText, TransactionUser* tu) : 
+TransactionState::TransactionState(TransactionController& controller, Machine m,
+                                   State s, const Data& id, MethodTypes method, const Data& methodText, TransactionUser* tu) :
    mController(controller),
-   mMachine(m), 
+   mMachine(m),
    mState(s),
    mIsAbandoned(false),
-   mIsReliable(true), // !jf! 
+   mIsReliable(true), // !jf!
    mNextTransmission(0),
    mDnsResult(0),
    mId(id),
@@ -69,18 +69,18 @@ TransactionState::TransactionState(TransactionController& controller, Machine m,
 }
 
 
-TransactionState* 
+TransactionState*
 TransactionState::makeCancelTransaction(TransactionState* tr, Machine machine, const Data& tid)
 {
-   TransactionState* cancel = new TransactionState(tr->mController, 
-                                                   machine, 
-                                                   Trying, 
-                                                   tid, 
-                                                   CANCEL, 
+   TransactionState* cancel = new TransactionState(tr->mController,
+                                                   machine,
+                                                   Trying,
+                                                   tid,
+                                                   CANCEL,
                                                    Data::Empty,
                                                    tr->mTransactionUser);
    // !jf! don't set this since it will be set by TransactionState::processReliability()
-   //cancel->mIsReliable = tr->mIsReliable;  
+   //cancel->mIsReliable = tr->mIsReliable;
    cancel->mResponseTarget = tr->mResponseTarget;
    cancel->mTarget = tr->mTarget;
    cancel->add(tid);
@@ -91,13 +91,13 @@ TransactionState::makeCancelTransaction(TransactionState* tr, Machine machine, c
    return cancel;
 }
 
-void 
+void
 TransactionState::handleInternalCancel(SipMessage* cancel,
                                        TransactionState& clientInvite)
 {
    TransactionState* state = TransactionState::makeCancelTransaction(&clientInvite, ClientNonInvite, clientInvite.mId+"cancel");
-   // Make sure the branch in the CANCEL matches the current 
-   // branch of the INVITE, in case we have done a DNS failover (the transport 
+   // Make sure the branch in the CANCEL matches the current
+   // branch of the INVITE, in case we have done a DNS failover (the transport
    // sequences could be different by now)
    cancel->header(h_Vias).front().param(p_branch)=clientInvite.mNextTransmission->const_header(h_Vias).front().param(p_branch);
    state->processClientNonInvite(cancel);
@@ -152,7 +152,7 @@ TransactionState::~TransactionState()
 
    //StackLog (<< "Deleting TransactionState " << mId << " : " << this);
    erase(mId);
-   
+
    delete mNextTransmission;
    delete mMethodText;
    mNextTransmission = 0;
@@ -166,7 +166,7 @@ TransactionState::processSipMessageAsNew(SipMessage* sip, TransactionController&
 {
    MethodTypes method=sip->method();
    StackLog (<< "No matching transaction for " << sip->brief());
-   TransactionUser* tu = 0;      
+   TransactionUser* tu = 0;
    if (sip->isExternal())
    {
       if (controller.mTuSelector.haveTransactionUsers() && sip->isRequest())
@@ -179,7 +179,7 @@ TransactionState::processSipMessageAsNew(SipMessage* sip, TransactionController&
             // If none of the TUs liked the request because of the Request-
             // Uri scheme, we should be returning a 416, for example.
             // ?bwc? Um, should we _really_ be doing this statelessly?
-            InfoLog( << "No TU found for message: " << sip->brief());               
+            InfoLog( << "No TU found for message: " << sip->brief());
             SipMessage* noMatch = Helper::makeResponse(*sip, 500);
             Tuple target(sip->getSource());
 
@@ -201,31 +201,31 @@ TransactionState::processSipMessageAsNew(SipMessage* sip, TransactionController&
          //InfoLog (<< "No TU associated with " << sip->brief());
       }
    }
-               
+
    if (sip->isRequest())
    {
       // create a new state object and insert in the TransactionMap
-               
+
       if (sip->isExternal()) // new sip msg from transport
       {
          if (method == INVITE)
          {
             // !rk! This might be needlessly created.  Design issue.
-            TransactionState* state = new TransactionState(controller, 
-                                                            ServerInvite, 
-                                                            Trying, 
-                                                            tid, 
+            TransactionState* state = new TransactionState(controller,
+                                                            ServerInvite,
+                                                            Trying,
+                                                            tid,
                                                             INVITE,
                                                             Data::Empty,
                                                             tu);
 
             state->mNextTransmission = state->make100(sip);
             state->mResponseTarget = sip->getSource(); // UACs source address
-            // since we don't want to reply to the source port if rport present 
+            // since we don't want to reply to the source port if rport present
             state->mResponseTarget.setPort(Helper::getPortForReply(*sip));
             state->mIsReliable = isReliable(state->mResponseTarget.getType());
             state->add(tid);
-               
+
             if (Timer::T100 == 0)
             {
                state->sendCurrentToWire(); // will get deleted when this is deleted
@@ -243,9 +243,9 @@ TransactionState::processSipMessageAsNew(SipMessage* sip, TransactionController&
          {
             // Note:  For cancel requests the tid member passed in will have the token "cancel" appended
             // to it, so that the cancel request can be treated as it's own transaction.  sip->getTransactionId()
-            // will be the original tid from the wire and should match the tid of the INVITE request being 
+            // will be the original tid from the wire and should match the tid of the INVITE request being
             // cancelled.
-            TransactionState* matchingInvite = 
+            TransactionState* matchingInvite =
                controller.mServerTransactionMap.find(sip->getTransactionId());
             if (matchingInvite == 0)
             {
@@ -254,7 +254,7 @@ TransactionState::processSipMessageAsNew(SipMessage* sip, TransactionController&
                SipMessage* response = Helper::makeResponse(*sip, 481);
                Tuple target(sip->getSource());
                controller.mTransportSelector.transmit(response, target);
-               
+
                delete response;
                return false;
             }
@@ -269,15 +269,15 @@ TransactionState::processSipMessageAsNew(SipMessage* sip, TransactionController&
          }
          else if (method != ACK)
          {
-            TransactionState* state = new TransactionState(controller, 
+            TransactionState* state = new TransactionState(controller,
                                                             ServerNonInvite,
-                                                            Trying, 
-                                                            tid, 
+                                                            Trying,
+                                                            tid,
                                                             method,
                                                             sip->methodStr(),
                                                             tu);
             state->mResponseTarget = sip->getSource();
-            // since we don't want to reply to the source port if rport present 
+            // since we don't want to reply to the source port if rport present
             state->mResponseTarget.setPort(Helper::getPortForReply(*sip));
             state->add(tid);
             state->mIsReliable = isReliable(state->mResponseTarget.getType());
@@ -285,7 +285,7 @@ TransactionState::processSipMessageAsNew(SipMessage* sip, TransactionController&
             state->sendToTU(sip);
             return true;
          }
-            
+
          // Incoming ACK just gets passed to the TU
          //StackLog(<< "Adding incoming message to TU fifo " << tid);
          TransactionState::sendToTU(tu, controller, sip);
@@ -294,10 +294,10 @@ TransactionState::processSipMessageAsNew(SipMessage* sip, TransactionController&
       {
          if (method == INVITE)
          {
-            TransactionState* state = new TransactionState(controller, 
-                                                            ClientInvite, 
-                                                            Calling, 
-                                                            tid, 
+            TransactionState* state = new TransactionState(controller,
+                                                            ClientInvite,
+                                                            Calling,
+                                                            tid,
                                                             INVITE,
                                                             Data::Empty,
                                                             tu);
@@ -306,10 +306,10 @@ TransactionState::processSipMessageAsNew(SipMessage* sip, TransactionController&
          }
          else if (method == ACK)
          {
-            TransactionState* state = new TransactionState(controller, 
-                                                            Stateless, 
-                                                            Calling, 
-                                                            tid, 
+            TransactionState* state = new TransactionState(controller,
+                                                            Stateless,
+                                                            Calling,
+                                                            tid,
                                                             ACK,
                                                             Data::Empty,
                                                             tu);
@@ -320,7 +320,7 @@ TransactionState::processSipMessageAsNew(SipMessage* sip, TransactionController&
          else if (method == CANCEL)
          {
             TransactionState* matchingInvite = controller.mClientTransactionMap.find(sip->getTransactionId());
-               
+
             if (matchingInvite == 0)
             {
                InfoLog (<< "No matching INVITE for incoming (from TU) CANCEL to uac");
@@ -347,12 +347,12 @@ TransactionState::processSipMessageAsNew(SipMessage* sip, TransactionController&
                handleInternalCancel(sip, *matchingInvite);
             }
          }
-         else 
+         else
          {
-            TransactionState* state = new TransactionState(controller, 
-                                                            ClientNonInvite, 
-                                                            Trying, 
-                                                            tid, 
+            TransactionState* state = new TransactionState(controller,
+                                                            ClientNonInvite,
+                                                            Trying,
+                                                            tid,
                                                             method,
                                                             sip->methodStr(),
                                                             tu);
@@ -371,11 +371,11 @@ TransactionState::processSipMessageAsNew(SipMessage* sip, TransactionController&
       else
       {
          StackLog (<< "forwarding stateless response: " << sip->brief());
-         TransactionState* state = 
-            new TransactionState(controller, 
-                                 Stateless, 
-                                 Calling, 
-                                 Data(StatelessIdCounter++), 
+         TransactionState* state =
+            new TransactionState(controller,
+                                 Stateless,
+                                 Calling,
+                                 Data(StatelessIdCounter++),
                                  method,
                                  sip->methodStr(),
                                  tu);
@@ -386,7 +386,7 @@ TransactionState::processSipMessageAsNew(SipMessage* sip, TransactionController&
    }
    else // wasn't a request or a response
    {
-      ErrLog (<< "Got a SipMessage that was neither a request nor response!" 
+      ErrLog (<< "Got a SipMessage that was neither a request nor response!"
                << sip->brief());
       return false;
    }
@@ -395,17 +395,17 @@ TransactionState::processSipMessageAsNew(SipMessage* sip, TransactionController&
 }
 
 void
-TransactionState::process(TransactionController& controller, 
+TransactionState::process(TransactionController& controller,
                            TransactionMessage* message)
 {
    {
       KeepAliveMessage* keepAlive = dynamic_cast<KeepAliveMessage*>(message);
       if (keepAlive)
       {
-         StackLog ( << "Sending keep alive to: " << keepAlive->getDestination());      
+         StackLog ( << "Sending keep alive to: " << keepAlive->getDestination());
          controller.mTransportSelector.transmit(keepAlive, keepAlive->getDestination());
          delete keepAlive;
-         return;      
+         return;
       }
 
       ConnectionTerminated* term = dynamic_cast<ConnectionTerminated*>(message);
@@ -465,9 +465,9 @@ TransactionState::process(TransactionController& controller,
          return;
       }
    }
-   
+
    // .bwc. We can't do anything without a tid here. Check this first.
-   Data tid;   
+   Data tid;
    try
    {
       tid = message->getTransactionId();
@@ -479,7 +479,7 @@ TransactionState::process(TransactionController& controller,
       delete message;
       return;
    }
-   
+
    SipMessage* sip = dynamic_cast<SipMessage*>(message);
    MethodTypes method = UNKNOWN;
 
@@ -491,15 +491,15 @@ TransactionState::process(TransactionController& controller,
       {
          controller.mStatsManager.received(sip);
       }
-      
+
       // .bwc. Check for error conditions we can respond to.
       if(sip->isRequest() && method != ACK)
       {
          // .bwc. If we are going to statelessly send a 503, we should do it
          // in the transport, before we do expensive stuff like basicCheck and
-         // stampReceived. If the TU fifo is backed up, we should send a 
+         // stampReceived. If the TU fifo is backed up, we should send a
          // _stateful_ 503 below. (And only if the specific TU that can handle
-         // this message is backed up; if other TUs are congested, we should let 
+         // this message is backed up; if other TUs are congested, we should let
          // it pass.)
          /*
          if(sip->isExternal() && (controller.isTUOverloaded() || controller.mStateMacFifo.isRejecting()))
@@ -509,7 +509,7 @@ TransactionState::process(TransactionController& controller,
               tryLater->header(h_RetryAfter).value() = controller.mStateMacFifo.getRetryAfter();
             else
               tryLater->header(h_RetryAfter).value() = 32 + (Random::getRandom() % 32);
-              
+
             //tryLater->header(h_RetryAfter).comment() = "Server busy TRANS";
             Tuple target(sip->getSource());
             delete sip;
@@ -518,13 +518,13 @@ TransactionState::process(TransactionController& controller,
             return;
          }
          */
-         
+
          if(sip->isInvalid())
          {
             handleBadRequest(*sip,controller);
             delete sip;
             return;
-         }         
+         }
       }
 
 #ifdef PEDANTIC_STACK
@@ -538,28 +538,28 @@ TransactionState::process(TransactionController& controller,
          {
             handleBadRequest(*sip,controller);
          }
-         
+
          InfoLog(<< "Exception caught by pedantic stack: " << e);
       }
-#endif      
-      
+#endif
+
       // This ensures that CANCEL requests form unique transactions
-      if (method == CANCEL) 
+      if (method == CANCEL)
       {
          tid += "cancel";
       }
    }
-      
+
    TransactionState* state = 0;
-   if (message->isClientTransaction()) 
+   if (message->isClientTransaction())
    {
       state = controller.mClientTransactionMap.find(tid);
    }
-   else 
+   else
    {
       state = controller.mServerTransactionMap.find(tid);
    }
-   
+
    if (state && sip && sip->isExternal())
    {
       // Various kinds of response fixup.
@@ -567,15 +567,15 @@ TransactionState::process(TransactionController& controller,
          state->mNextTransmission)
       {
          // .bwc. This code (if enabled) ensures that responses have the same
-         // CallId and tags as the request did (excepting the introduction of a 
-         // remote tag). This is to protect dialog-stateful TUs that don't react 
-         // gracefully when a stupid/malicious endpoint fiddles with the tags 
+         // CallId and tags as the request did (excepting the introduction of a
+         // remote tag). This is to protect dialog-stateful TUs that don't react
+         // gracefully when a stupid/malicious endpoint fiddles with the tags
          // and/or CallId when it isn't supposed to. (DUM is one such TU)
          if(state->mController.getFixBadDialogIdentifiers())
          {
             if(sip->const_header(h_CallId).isWellFormed())
             {
-               if(!(sip->const_header(h_CallId) == 
+               if(!(sip->const_header(h_CallId) ==
                            state->mNextTransmission->const_header(h_CallId)))
                {
                   InfoLog(<< "Other end modified our Call-Id... correcting.");
@@ -587,7 +587,7 @@ TransactionState::process(TransactionController& controller,
                InfoLog(<< "Other end corrupted our CallId... correcting.");
                sip->header(h_CallId) = state->mNextTransmission->const_header(h_CallId);
             }
-   
+
             const NameAddr& from = state->mNextTransmission->const_header(h_From);
             if(sip->const_header(h_From).isWellFormed())
             {
@@ -615,7 +615,7 @@ TransactionState::process(TransactionController& controller,
                // Whole header is hosed, overwrite.
                sip->header(h_From) = from;
             }
-   
+
             const NameAddr& to = state->mNextTransmission->const_header(h_To);
             if(sip->const_header(h_To).isWellFormed())
             {
@@ -639,8 +639,8 @@ TransactionState::process(TransactionController& controller,
          }
 
          // .bwc. This code (if enabled) ensures that responses have the same
-         // CSeq number as the request did. This is to protect TUs that don't 
-         // react gracefully when a stupid/malicious endpoint fiddles with the 
+         // CSeq number as the request did. This is to protect TUs that don't
+         // react gracefully when a stupid/malicious endpoint fiddles with the
          // CSeq number. (This is a very cheap check; we already parse the CSeq
          // for incoming messages)
          if(state->mController.getFixBadCSeqNumbers())
@@ -655,12 +655,12 @@ TransactionState::process(TransactionController& controller,
       }
       // .bwc. This code ensures that the transaction state-machine can recover
       // from ACK/200 with the same tid as the original INVITE. This problem is
-      // stupidly common. 
+      // stupidly common.
       if(sip->isRequest() && method == ACK && !state->mAckIsValid)
       {
          // Must have received an ACK to a 200;
          // We will never respond to this, so nothing will need this tid for
-         // driving transaction state. Additionally, 
+         // driving transaction state. Additionally,
          InfoLog(<<"Someone sent us an ACK/200 with the same tid as the "
                      "original INVITE. This is bad behavior, and should be "
                      "corrected in the client.");
@@ -760,24 +760,24 @@ TransactionState::process(TransactionController& controller,
          bool processed = processSipMessageAsNew(sip, controller, tid);
          if (!processed)
          {
-            delete sip;      
+            delete sip;
          }
       }
-      catch(resip::BaseException& e)   
+      catch(resip::BaseException& e)
       {
-         StackLog ( << "Got badly formatted sip message, error: " << e.what());      
+         StackLog ( << "Got badly formatted sip message, error: " << e.what());
          if(sip->isRequest() && sip->method()!=ACK)
          {
             handleBadRequest(*sip, controller);
-         }         
-         delete sip;      
+         }
+         delete sip;
       }
-      catch(std::exception& err)      
+      catch(std::exception& err)
       {
          StackLog ( << "Got error: " << err.what());
          delete sip;
       }
-   } 
+   }
    else // timer or other non-sip msg
    {
       //StackLog (<< "discarding non-sip message: " << message->brief());
@@ -793,28 +793,28 @@ TransactionState::processTimer(TransactionController& controller,
 
    if(controller.getRejectionBehavior()==CongestionManager::REJECTING_NON_ESSENTIAL)
    {
-      // .bwc. State machine fifo is backed up; we probably should not be 
-      // retransmitting anything right now. If we have a retransmit timer, 
+      // .bwc. State machine fifo is backed up; we probably should not be
+      // retransmitting anything right now. If we have a retransmit timer,
       // reschedule for later, but don't retransmit.
       switch(message->getType())
       {
          case Timer::TimerA: // doubling
-            controller.mTimers.add(Timer::TimerA, 
-                                    tid, 
+            controller.mTimers.add(Timer::TimerA,
+                                    tid,
                                     message->getDuration()*2);
             delete message;
             return;
          case Timer::TimerE1:// doubling, until T2
          case Timer::TimerG: // doubling, until T2
-            controller.mTimers.add(message->getType(), 
-                                    tid, 
+            controller.mTimers.add(message->getType(),
+                                    tid,
                                     resipMin(message->getDuration()*2,
                                              Timer::T2));
             delete message;
             return;
          case Timer::TimerE2:// just reset
-            controller.mTimers.add(Timer::TimerE2, 
-                                    tid, 
+            controller.mTimers.add(Timer::TimerE2,
+                                    tid,
                                     Timer::T2);
             delete message;
             return;
@@ -826,7 +826,7 @@ TransactionState::processTimer(TransactionController& controller,
    TransactionState* state = 0;
    if (message->isClientTransaction()) state = controller.mClientTransactionMap.find(tid);
    else state = controller.mServerTransactionMap.find(tid);
-   
+
    if (state) // found transaction for timer
    {
       StackLog (<< "Found matching transaction for " << message->brief() << " -> " << *state);
@@ -905,7 +905,7 @@ TransactionState::processStateless(TransactionMessage* message)
    else if (isTransportError(message))
    {
       processTransportFailure(message);
-      
+
       delete message;
       delete this;
    }
@@ -940,7 +940,7 @@ TransactionState::processStateless(TransactionMessage* message)
    }
 }
 
-void 
+void
 TransactionState::saveOriginalContactAndVia(const SipMessage& sip)
 {
    if(sip.exists(h_Contacts) && sip.const_header(h_Contacts).size() == 1 &&
@@ -956,7 +956,7 @@ void TransactionState::restoreOriginalContactAndVia()
    if (mOriginalContact.get())
    {
       mNextTransmission->header(h_Contacts).front() = *mOriginalContact;
-   }                  
+   }
    if (mOriginalVia.get())
    {
       mOriginalVia->param(p_branch).incrementTransportSequence();
@@ -966,7 +966,7 @@ void TransactionState::restoreOriginalContactAndVia()
 
 void
 TransactionState::processClientNonInvite(TransactionMessage* msg)
-{ 
+{
    StackLog (<< "TransactionState::processClientNonInvite: " << msg->brief());
 
    if (isRequest(msg) && isFromTU(msg))
@@ -995,7 +995,7 @@ TransactionState::processClientNonInvite(TransactionMessage* msg)
                mController.mTimers.add(Timer::TimerE2, mId, Timer::T2 );
             }
             mState = Proceeding;
-            sendToTU(msg); // don't delete            
+            sendToTU(msg); // don't delete
          }
          else
          {
@@ -1019,7 +1019,7 @@ TransactionState::processClientNonInvite(TransactionMessage* msg)
             assert(0);
             delete sip;
          }
-         
+
          if (mIsReliable)
          {
             terminateClientTransaction(mId);
@@ -1078,7 +1078,7 @@ TransactionState::processClientNonInvite(TransactionMessage* msg)
                sendCurrentToWire();
                delete timer;
             }
-            else 
+            else
             {
                // ignore
                delete msg;
@@ -1094,7 +1094,7 @@ TransactionState::processClientNonInvite(TransactionMessage* msg)
                if(mWaitingForDnsResult)
                {
                   WarningLog(<< "Transaction timed out while waiting for DNS "
-                              "result uri=" << 
+                              "result uri=" <<
                               mNextTransmission->const_header(h_RequestLine).uri());
                   sendToTU(Helper::makeResponse(*mNextTransmission, 503, "DNS Timeout"));
                }
@@ -1105,7 +1105,7 @@ TransactionState::processClientNonInvite(TransactionMessage* msg)
                terminateClientTransaction(mId);
                delete this;
             }
-            
+
             delete msg;
             break;
 
@@ -1153,7 +1153,7 @@ TransactionState::processClientInvite(TransactionMessage* msg)
       switch (sip->method())
       {
          // Received INVITE request from TU="Transaction User", Start Timer B which controls
-         // transaction timeouts. 
+         // transaction timeouts.
          case INVITE:
             if(mState==Calling && !mNextTransmission && mMsgToRetransmit.empty())
             {
@@ -1168,7 +1168,7 @@ TransactionState::processClientInvite(TransactionMessage* msg)
                delete sip;
             }
             break;
-            
+
          case CANCEL:
             assert(0);
             delete msg;
@@ -1193,7 +1193,7 @@ TransactionState::processClientInvite(TransactionMessage* msg)
                "Proceeding" state, the client transaction SHOULD NOT retransmit the
                request any longer (this will be Handled in  "else if (isTimer(msg))")
                The Retransmissions will be stopped, Not by Cancelling Timers but
-               by Ignoring the fired Timers depending upon the State which stack is in.   
+               by Ignoring the fired Timers depending upon the State which stack is in.
             */
             if (code >= 100 && code < 200) // 1XX
             {
@@ -1209,8 +1209,8 @@ TransactionState::processClientInvite(TransactionMessage* msg)
                      mIsAbandoned=false;
                   }
                   // !bwc! We have gotten a response. We don't need to
-                  // retransmit the original INVITE anymore (so we clear mMsgToRetransmit), 
-                  // but we do need to retain the full original INVITE until we get a final 
+                  // retransmit the original INVITE anymore (so we clear mMsgToRetransmit),
+                  // but we do need to retain the full original INVITE until we get a final
                   // response, in case we need to forge an ACK.
                   mMsgToRetransmit.clear();
                   sendToTU(sip); // don't delete msg
@@ -1223,8 +1223,8 @@ TransactionState::processClientInvite(TransactionMessage* msg)
 
             /* When in either the "Calling" or "Proceeding" states, reception of a
                2xx response MUST cause the client transaction to enter the
-               "Terminated" state, and the response MUST be passed up to the TU 
-               State Machine is changed to Stale since, we wanted to ensure that 
+               "Terminated" state, and the response MUST be passed up to the TU
+               State Machine is changed to Stale since, we wanted to ensure that
                all 2xx gets to TU
             */
             else if (code >= 200 && code < 300)
@@ -1262,15 +1262,15 @@ TransactionState::processClientInvite(TransactionMessage* msg)
                   SipMessage* ack = Helper::makeFailureAck(*mNextTransmission, *sip);
                   mNextTransmission->copyOutboundDecoratorsToStackFailureAck(*ack);
                   resetNextTransmission(ack);
-                  
+
                   // want to use the same transport as was selected for Invite
                   assert(mTarget.getType() != UNKNOWN_TRANSPORT);
                   sendCurrentToWire();
                   sendToTU(sip); // don't delete msg
                   terminateClientTransaction(mId);
-                  
+
                   // !bwc! We only do this because we are assured the ACK
-                  // will make it to the other end; if we are using an 
+                  // will make it to the other end; if we are using an
                   // unreliable transport, we need to stick around to absorb
                   // retransmissions of the response.
                   delete this;
@@ -1281,8 +1281,8 @@ TransactionState::processClientInvite(TransactionMessage* msg)
                   {
                      // MUST pass the received response up to the TU, and the client
                      // transaction MUST generate an ACK request, even if the transport is
-                     // reliable, if transport is Unreliable then Fire the Timer D which 
-                     // take care of re-Transmission of ACK 
+                     // reliable, if transport is Unreliable then Fire the Timer D which
+                     // take care of re-Transmission of ACK
                      mState = Completed;
                      mController.mTimers.add(Timer::TimerD, mId, Timer::TD );
                      SipMessage* ack = Helper::makeFailureAck(*mNextTransmission, *sip);
@@ -1324,7 +1324,7 @@ TransactionState::processClientInvite(TransactionMessage* msg)
                assert(0);
             }
             break;
-            
+
          case CANCEL:
             assert(0);
             delete sip;
@@ -1342,14 +1342,14 @@ TransactionState::processClientInvite(TransactionMessage* msg)
 
       TimerMessage* timer = dynamic_cast<TimerMessage*>(msg);
       StackLog (<< "timer fired: " << *timer);
-      
+
       switch (timer->getType())
       {
          case Timer::TimerA:
             if (mState == Calling && !mIsAbandoned)
             {
                unsigned long d = timer->getDuration()*2;
-               // TimerA is supposed to double with each retransmit RFC3261 17.1.1          
+               // TimerA is supposed to double with each retransmit RFC3261 17.1.1
 
                mController.mTimers.add(Timer::TimerA, mId, d);
                DebugLog (<< "Retransmitting INVITE ");
@@ -1366,7 +1366,7 @@ TransactionState::processClientInvite(TransactionMessage* msg)
                if(mWaitingForDnsResult)
                {
                   WarningLog(<< "Transaction timed out while waiting for DNS "
-                              "result uri=" << 
+                              "result uri=" <<
                               mNextTransmission->const_header(h_RequestLine).uri());
                   sendToTU(Helper::makeResponse(*mNextTransmission, 503, "DNS Timeout"));
                }
@@ -1390,14 +1390,14 @@ TransactionState::processClientInvite(TransactionMessage* msg)
             // !ah! Cancelled Invite Cleanup Timer fired.
             if (mState == Proceeding)
             {
-               assert(mNextTransmission && mNextTransmission->isRequest() && 
+               assert(mNextTransmission && mNextTransmission->isRequest() &&
                         mNextTransmission->method() == INVITE);
                StackLog (<< "Timer::TimerCleanUp: " << *this << std::endl << *mNextTransmission);
                InfoLog(<<"Making 408 for canceled invite that received no response: "<< mNextTransmission->brief());
                if(mWaitingForDnsResult)
                {
                   WarningLog(<< "Transaction timed out while waiting for DNS "
-                              "result uri=" << 
+                              "result uri=" <<
                               mNextTransmission->const_header(h_RequestLine).uri());
                   sendToTU(Helper::makeResponse(*mNextTransmission, 503, "DNS Timeout"));
                }
@@ -1475,9 +1475,9 @@ TransactionState::processServerNonInvite(TransactionMessage* msg)
          }
          else
          {
-            // We have already sent a 100, but we have just received a retransmission.  Requests 
+            // We have already sent a 100, but we have just received a retransmission.  Requests
             // likely crossed on the wire.  We need to respond with another 100, but the last one was
-            // cleared so re-create the 100 now. 
+            // cleared so re-create the 100 now.
             SipMessage* sip = dynamic_cast<SipMessage*>(msg);
             if (sip && mMsgToRetransmit.empty() && !mNextTransmission)
             {
@@ -1489,7 +1489,7 @@ TransactionState::processServerNonInvite(TransactionMessage* msg)
       }
       else
       {
-         CritLog (<< "Fatal error in TransactionState::processServerNonInvite " 
+         CritLog (<< "Fatal error in TransactionState::processServerNonInvite "
                   << msg->brief()
                   << " state=" << *this);
          assert(0);
@@ -1522,9 +1522,9 @@ TransactionState::processServerNonInvite(TransactionMessage* msg)
             resetNextTransmission(sip);
             sendCurrentToWire();
             terminateServerTransaction(mId);
-            
+
             // !bwc! We can only do this because we are in a reliable
-            // transport, and do not need to hang around to soak up 
+            // transport, and do not need to hang around to soak up
             // retransmissions.
             delete this;
          }
@@ -1544,7 +1544,7 @@ TransactionState::processServerNonInvite(TransactionMessage* msg)
             }
             else
             {
-               CritLog (<< "Fatal error in TransactionState::processServerNonInvite " 
+               CritLog (<< "Fatal error in TransactionState::processServerNonInvite "
                         << msg->brief()
                         << " state=" << *this);
                assert(0);
@@ -1600,16 +1600,16 @@ TransactionState::processServerNonInvite(TransactionMessage* msg)
       {
          mIsAbandoned = true;
 
-         // !bwc! We could check to see if we have a 100 lying around, and 
-         // convert it into a 500 for immediate transmission, but it is not 
-         // clear that this is a good idea, especially if the TU has abandoned 
-         // this transaction after the remote endpoint has stopped 
+         // !bwc! We could check to see if we have a 100 lying around, and
+         // convert it into a 500 for immediate transmission, but it is not
+         // clear that this is a good idea, especially if the TU has abandoned
+         // this transaction after the remote endpoint has stopped
          // retransmitting. Maybe we could use a time-stamp to help here? Would
          // it be worth the extra memory footprint?
 
          if (mIsReliable)
          {
-            // If we haven't sent a 500 yet, we never will (no retransmissions 
+            // If we haven't sent a 500 yet, we never will (no retransmissions
             // to make the response with).
             terminateServerTransaction(mId);
             delete this;
@@ -1674,7 +1674,7 @@ TransactionState::processServerInvite(TransactionMessage* msg)
                  passed from the TU for this transaction.
                */
                //StackLog (<< "Received invite from wire - forwarding to TU state=" << mState);
-               
+
                // !bwc! If we have nothing to respond with, make something.
                if (mMsgToRetransmit.empty() && !mNextTransmission)
                {
@@ -1689,7 +1689,7 @@ TransactionState::processServerInvite(TransactionMessage* msg)
                delete msg;
             }
             break;
-            
+
          case ACK:
             /*
               If an ACK is received while the server transaction is in the
@@ -1702,7 +1702,7 @@ TransactionState::processServerInvite(TransactionMessage* msg)
                {
                   //StackLog (<< "Received ACK in Completed (reliable) - delete transaction");
                   terminateServerTransaction(mId);
-                  delete this; 
+                  delete this;
                   delete msg;
                }
                else
@@ -1779,9 +1779,9 @@ TransactionState::processServerInvite(TransactionMessage* msg)
                   StackLog (<< *this);
                   resetNextTransmission(sip); // may be replacing the 100
                   sendCurrentToWire();
-                  
+
                   // Keep the StaleServer transaction around, so we can keep the
-                  // source Tuple that the request was received on. 
+                  // source Tuple that the request was received on.
                   //terminateServerTransaction(mId);
                   mMachine = ServerStale;
                   mController.mTimers.add(Timer::TimerStaleServer, mId, Timer::TS );
@@ -1796,11 +1796,11 @@ TransactionState::processServerInvite(TransactionMessage* msg)
             {
                /*
                  While in the "Proceeding" state, if the TU passes a response with
-                 status code from 300 to 699 to the server transaction, For unreliable 
-                 transports,timer G is set to fire in T1 seconds, and is not set to 
-                 fire for reliable transports.when the "Completed" state is entered, 
-                 timer H MUST be set to fire in 64*T1 seconds for all transports.  
-                 Timer H determines when the server transaction abandons retransmitting 
+                 status code from 300 to 699 to the server transaction, For unreliable
+                 transports,timer G is set to fire in T1 seconds, and is not set to
+                 fire for reliable transports.when the "Completed" state is entered,
+                 timer H MUST be set to fire in 64*T1 seconds for all transports.
+                 Timer H determines when the server transaction abandons retransmitting
                  the response
                */
 
@@ -1829,12 +1829,12 @@ TransactionState::processServerInvite(TransactionMessage* msg)
                delete msg;
             }
             break;
-            
+
          case CANCEL:
             assert(0);
             delete sip;
             break;
-            
+
          default:
             //StackLog (<< "Received response to non invite or cancel. Ignoring");
             delete msg;
@@ -1860,10 +1860,10 @@ TransactionState::processServerInvite(TransactionMessage* msg)
               ACK was never received.  In this case, the server transaction MUST
               transition to the "Terminated" state, and MUST indicate to the TU
               that a transaction failure has occurred. WHY we need to inform TU
-              for Failure cases ACK ? do we really need to do this ???       
+              for Failure cases ACK ? do we really need to do this ???
 
               !jf! this used to re-add TimerH if there was an associated CANCEL
-              transaction. Don't know why. 
+              transaction. Don't know why.
             */
          case Timer::TimerH:
          case Timer::TimerI:
@@ -1887,7 +1887,7 @@ TransactionState::processServerInvite(TransactionMessage* msg)
                //StackLog (<< "TimerTrying fired. Not in Trying state. Ignoring");
             }
             break;
-            
+
          default:
             CritLog(<<"unexpected timer fired: " << timer->getType());
             assert(0); // programming error if any other timer fires
@@ -2058,7 +2058,7 @@ TransactionState::processServerStale(TransactionMessage* msg)
    else if (isResponse(msg) && isFromTU(msg))
    {
       resetNextTransmission(sip);
-      sendCurrentToWire(); 
+      sendCurrentToWire();
    }
    else if(dynamic_cast<DnsResultMessage*>(msg))
    {
@@ -2072,7 +2072,7 @@ TransactionState::processServerStale(TransactionMessage* msg)
    }
    else
    {
-      // .bwc. This can very easily be triggered by a stupid/malicious 
+      // .bwc. This can very easily be triggered by a stupid/malicious
       // endpoint. This is not an error in our code. Do not ErrLog this.
       InfoLog(<<"ServerStale unexpected condition, dropping message.");
       if (sip)
@@ -2089,8 +2089,8 @@ TransactionState::processNoDnsResults()
 {
    if(!mNextTransmission || mNextTransmission->method()==ACK)
    {
-      // This is probably an ACK; since we know we will never need to send a 
-      // response to an ACK, we delete mNextTransmission as soon as we 
+      // This is probably an ACK; since we know we will never need to send a
+      // response to an ACK, we delete mNextTransmission as soon as we
       // serialize it.
       return;
    }
@@ -2160,7 +2160,7 @@ TransactionState::processNoDnsResults()
 
    response->header(h_Warnings).push_back(warning);
 
-   sendToTU(response); 
+   sendToTU(response);
    terminateClientTransaction(mId);
    if (mMachine != Stateless)
    {
@@ -2183,9 +2183,9 @@ TransactionState::processTransportFailure(TransactionMessage* msg)
    }
 
    if (mNextTransmission &&  // Note:  If we just transmitted an ACK then mNextTransmission is cleared, so this check is necessary
-       mNextTransmission->isRequest() && 
+       mNextTransmission->isRequest() &&
        mNextTransmission->method() == CANCEL &&
-       mState != Completed && 
+       mState != Completed &&
        mState != Terminated)
    {
       WarningLog (<< "Failed to deliver a CANCEL request");
@@ -2202,7 +2202,7 @@ TransactionState::processTransportFailure(TransactionMessage* msg)
       warning.code() = 399;
       warning.text() = "Failed to deliver CANCEL using the same transport as the INVITE was used";
       response->header(h_Warnings).push_back(warning);
-         
+
       sendToTU(response);
       return;
    }
@@ -2259,7 +2259,7 @@ TransactionState::processTransportFailure(TransactionMessage* msg)
 
                // !bwc!
                // An interesting consequence occurs if our failover ultimately
-               // sends to the same instance of a resip stack; we increment the 
+               // sends to the same instance of a resip stack; we increment the
                // transport sequence in our branch parameter, but any resip-based
                // stack will ignore this change, and process this "new" request as
                // a retransmission! Furthermore, our state will be out of phase
@@ -2271,7 +2271,7 @@ TransactionState::processTransportFailure(TransactionMessage* msg)
             shouldFailover=true;
          }
       }
-   
+
       if(shouldFailover)
       {
          InfoLog (<< "Try sending request to a different dns result");
@@ -2287,7 +2287,7 @@ TransactionState::processTransportFailure(TransactionMessage* msg)
                processReliability(mTarget.getType());
                sendCurrentToWire();
                break;
-            
+
             case DnsResult::Pending:
                InfoLog(<< "We have a DNS query pending.");
                mWaitingForDnsResult=true;
@@ -2349,9 +2349,9 @@ void
 TransactionState::handleSync(DnsResult* result)
 {
    StackLog (<< *this << " got DNS result: " << *result);
-   
+
    // .bwc. Were we expecting something from mDnsResult?
-   if (mWaitingForDnsResult) 
+   if (mWaitingForDnsResult)
    {
       assert(mDnsResult);
       switch (mDnsResult->available())
@@ -2366,7 +2366,7 @@ TransactionState::handleSync(DnsResult* result)
             processReliability(mTarget.getType());
             sendCurrentToWire();
             break;
-            
+
          case DnsResult::Finished:
             mWaitingForDnsResult=false;
             processNoDnsResults();
@@ -2374,7 +2374,7 @@ TransactionState::handleSync(DnsResult* result)
 
          case DnsResult::Pending:
             break;
-            
+
          case DnsResult::Destroyed:
          default:
             assert(0);
@@ -2399,7 +2399,7 @@ TransactionState::processReliability(TransportType type)
                case ClientNonInvite:
                   mController.mTimers.add(Timer::TimerE1, mId, Timer::T1 );
                   break;
-                  
+
                case ClientInvite:
                   mController.mTimers.add(Timer::TimerA, mId, Timer::T1 );
                   break;
@@ -2409,7 +2409,7 @@ TransactionState::processReliability(TransportType type)
             }
          }
          break;
-         
+
       default:
          if (!mIsReliable)
          {
@@ -2430,7 +2430,7 @@ simpleTupleForUri(const Uri& uri)
    int port = uri.port();
 
    resip::TransportType transport = UNKNOWN_TRANSPORT;
- 
+
   if (uri.exists(p_transport))
    {
       transport = Tuple::toTransport(uri.param(p_transport));
@@ -2461,14 +2461,14 @@ simpleTupleForUri(const Uri& uri)
 }
 
 void
-TransactionState::sendCurrentToWire() 
+TransactionState::sendCurrentToWire()
 {
    if(!mMsgToRetransmit.empty())
    {
       if(mController.mStack.statisticsManagerEnabled())
       {
-         mController.mStatsManager.retransmitted(mCurrentMethodType, 
-                                                   isClient(), 
+         mController.mStatsManager.retransmitted(mCurrentMethodType,
+                                                   isClient(),
                                                    mCurrentResponseCode);
       }
 
@@ -2484,7 +2484,7 @@ TransactionState::sendCurrentToWire()
          if(mTarget.getType() != UNKNOWN_TRANSPORT) // mTarget is set, so just send.
          {
             transmitted=mController.mTransportSelector.transmit(
-                        sip, 
+                        sip,
                         mTarget,
                         mIsReliable ? 0 : &mMsgToRetransmit);
          }
@@ -2495,13 +2495,13 @@ TransactionState::sendCurrentToWire()
                // ?bwc? Maybe we should be nice to the TU and do DNS in this case?
                assert(sip->getDestination().getType() != UNKNOWN_TRANSPORT);
 
-               // .bwc. We have the FlowKey. This completely specifies our 
+               // .bwc. We have the FlowKey. This completely specifies our
                // Transport (and Connection, if applicable). No DNS required.
                DebugLog(<< "Sending to tuple: " << sip->getDestination());
                mTarget = sip->getDestination();
                processReliability(mTarget.getType());
                transmitted=mController.mTransportSelector.transmit(
-                           sip, 
+                           sip,
                            mTarget,
                            mIsReliable ? 0 : &mMsgToRetransmit);
             }
@@ -2519,7 +2519,7 @@ TransactionState::sendCurrentToWire()
                else // ... but our DNS query isn't done yet.
                {
                   // .bwc. While the resolver was attempting to find a target, another
-                  // request came down from the TU. This could be a bug in the TU, or 
+                  // request came down from the TU. This could be a bug in the TU, or
                   // could be a retransmission of an ACK/200. Either way, we cannot
                   // expect to ever be able to send this request (nowhere to store it
                   // temporarily).
@@ -2544,12 +2544,12 @@ TransactionState::sendCurrentToWire()
          if (sip->hasForceTarget())
          {
             // ?bwc? Override the target for a single response? Should we even
-            // allow this? What about client transactions? Should we overwrite 
+            // allow this? What about client transactions? Should we overwrite
             // mResponseTarget here? I don't think this has been thought out properly.
             Tuple target = simpleTupleForUri(sip->getForceTarget());
             StackLog(<<"!ah! response with force target going to : "<<target);
             transmitted=mController.mTransportSelector.transmit(
-                        sip, 
+                        sip,
                         mTarget,
                         mIsReliable ? 0 : &mMsgToRetransmit);
          }
@@ -2558,23 +2558,23 @@ TransactionState::sendCurrentToWire()
             if (sip->const_header(h_Vias).front().exists(p_rport) && sip->const_header(h_Vias).front().param(p_rport).hasValue())
             {
                // ?bwc? This was not setting the port in mResponseTarget before. Why would
-               // the rport be different than the port in mResponseTarget? Didn't we 
-               // already set this? Maybe the TU messed with it? If so, why should we pay 
+               // the rport be different than the port in mResponseTarget? Didn't we
+               // already set this? Maybe the TU messed with it? If so, why should we pay
                // attention to it? Again, this hasn't been thought out.
                mResponseTarget.setPort(sip->const_header(h_Vias).front().param(p_rport).port());
                StackLog(<< "rport present in response: " << mResponseTarget.getPort());
             }
-   
+
             StackLog(<< "tid=" << sip->getTransactionId() << " sending to : " << mResponseTarget);
             transmitted=mController.mTransportSelector.transmit(
-                        sip, 
+                        sip,
                         mResponseTarget,
                         mIsReliable ? 0 : &mMsgToRetransmit);
          }
       }
 
       // !bwc! If we don't have DNS results yet, or TransportSelector::transmit
-      // fails, we hang on to the full original SipMessage, in the hope that 
+      // fails, we hang on to the full original SipMessage, in the hope that
       // next time it works.
       if (transmitted)
       {
@@ -2590,7 +2590,7 @@ TransactionState::sendCurrentToWire()
          }
 
          // !bwc! If mNextTransmission is a non-ACK request, we need to save the
-         // initial request in case we need to send a simulated 408 or a 503 to 
+         // initial request in case we need to send a simulated 408 or a 503 to
          // the TU (at least, until we get a response back)
          if(!mNextTransmission->isRequest() || mNextTransmission->method()==ACK)
          {
@@ -2618,20 +2618,20 @@ TransactionState::sendToTU(TransactionMessage* msg)
             // blacklist last target.
             // .bwc. If there is no Retry-After, we do not blacklist
             // (see RFC 3261 sec 21.5.4 para 1)
-            if(sipMsg->exists(resip::h_RetryAfter) && 
+            if(sipMsg->exists(resip::h_RetryAfter) &&
                sipMsg->const_header(resip::h_RetryAfter).isWellFormed())
             {
                unsigned int relativeExpiry= sipMsg->const_header(resip::h_RetryAfter).value();
-               
+
                if(relativeExpiry!=0)
                {
                   mDnsResult->blacklistLast(resip::Timer::getTimeMs()+relativeExpiry*1000);
                }
             }
-            
+
             break;
          case 408:
-            if(sipMsg->getReceivedTransport() == 0 && 
+            if(sipMsg->getReceivedTransport() == 0 &&
                   (mState == Trying || mState==Calling))  // only greylist if internally generated and we haven't received any responses yet
             {
                // greylist last target.
@@ -2674,7 +2674,7 @@ TransactionState::sendToTU(TransactionMessage* msg)
                // .bwc. This is new work. Reject.
                SipMessage* response(Helper::makeResponse(*sipMsg, 503));
                delete sipMsg;
-               
+
                UInt16 retryAfter=mController.mTuSelector.getExpectedWait(mTransactionUser);
                response->header(h_RetryAfter).value()=retryAfter;
                response->setFromTU();
@@ -2705,18 +2705,18 @@ TransactionState::sendToTU(TransactionMessage* msg)
       }
       else
       {
-         // .bwc. This is some sort of timer, or other message. If we don't know 
+         // .bwc. This is some sort of timer, or other message. If we don't know
          // any better, we need to assume this is essential for the safe
          // operation of the TU.
       }
    }
-   
+
    TransactionState::sendToTU(mTransactionUser, mController, msg);
 }
 
 void
-TransactionState::sendToTU(TransactionUser* tu, TransactionController& controller, TransactionMessage* msg) 
-{   
+TransactionState::sendToTU(TransactionUser* tu, TransactionController& controller, TransactionMessage* msg)
+{
    msg->setTransactionUser(tu);
    controller.mTuSelector.add(msg, TimeLimitFifo<Message>::InternalElement);
 }
@@ -2756,7 +2756,7 @@ TransactionState::erase(const Data& tid)
 bool
 TransactionState::isRequest(TransactionMessage* msg) const
 {
-   SipMessage* sip = dynamic_cast<SipMessage*>(msg);   
+   SipMessage* sip = dynamic_cast<SipMessage*>(msg);
    return sip && sip->isRequest();
 }
 
@@ -2809,13 +2809,13 @@ TransactionState::isTransportError(TransactionMessage* msg) const
    return dynamic_cast<TransportFailure*>(msg) != 0;
 }
 
-bool 
+bool
 TransactionState::isAbandonServerTransaction(TransactionMessage* msg) const
 {
    return dynamic_cast<AbandonServerTransaction*>(msg) != 0;
 }
 
-bool 
+bool
 TransactionState::isCancelClientTransaction(TransactionMessage* msg) const
 {
    return dynamic_cast<CancelClientInviteTransaction*>(msg) != 0;
@@ -2835,7 +2835,7 @@ void
 TransactionState::terminateClientTransaction(const Data& tid)
 {
    mState = Terminated;
-   if (mController.mTuSelector.isTransactionUserStillRegistered(mTransactionUser) && 
+   if (mController.mTuSelector.isTransactionUserStillRegistered(mTransactionUser) &&
        mTransactionUser->isRegisteredForTransactionTermination())
    {
       //StackLog (<< "Terminate client transaction " << tid);
@@ -2847,7 +2847,7 @@ void
 TransactionState::terminateServerTransaction(const Data& tid)
 {
    mState = Terminated;
-   if (mController.mTuSelector.isTransactionUserStillRegistered(mTransactionUser) && 
+   if (mController.mTuSelector.isTransactionUserStillRegistered(mTransactionUser) &&
        mTransactionUser->isRegisteredForTransactionTermination())
    {
       //StackLog (<< "Terminate server transaction " << tid);
@@ -2855,7 +2855,7 @@ TransactionState::terminateServerTransaction(const Data& tid)
    }
 }
 
-bool 
+bool
 TransactionState::isClient() const
 {
    switch(mMachine)
@@ -2875,7 +2875,7 @@ TransactionState::isClient() const
    return false;
 }
 
-EncodeStream& 
+EncodeStream&
 resip::operator<<(EncodeStream& strm, const resip::TransactionState& state)
 {
    strm << "tid=" << state.mId << " [ ";
@@ -2903,7 +2903,7 @@ resip::operator<<(EncodeStream& strm, const resip::TransactionState& state)
          strm << "ServerStale";
          break;
    }
-   
+
    strm << "/";
    switch (state.mState)
    {
@@ -2929,7 +2929,7 @@ resip::operator<<(EncodeStream& strm, const resip::TransactionState& state)
          strm << "Bogus";
          break;
    }
-   
+
    strm << (state.mIsReliable ? " reliable" : " unreliable");
    strm << " target=" << state.mResponseTarget;
    //if (state.mTransactionUser) strm << " tu=" << *state.mTransactionUser;
@@ -2938,28 +2938,32 @@ resip::operator<<(EncodeStream& strm, const resip::TransactionState& state)
    return strm;
 }
 
+bool TransactionState::isBlackListException( const Tuple& t )
+{
+    return mTransactionUser ? mTransactionUser->isBlackListException( t ) : false;
+}
 
 /* Local Variables: */
 /* c-file-style: "ellemtel" */
 /* End: */
 
 /* ====================================================================
- * The Vovida Software License, Version 1.0 
- * 
+ * The Vovida Software License, Version 1.0
+ *
  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 
+ *
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
- * 
+ *
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in
  *    the documentation and/or other materials provided with the
  *    distribution.
- * 
+ *
  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
  *    and "Vovida Open Communication Application Library (VOCAL)" must
  *    not be used to endorse or promote products derived from this
@@ -2969,7 +2973,7 @@ resip::operator<<(EncodeStream& strm, const resip::TransactionState& state)
  * 4. Products derived from this software may not be called "VOCAL", nor
  *    may "VOCAL" appear in their name, without prior written
  *    permission of Vovida Networks, Inc.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
@@ -2983,9 +2987,9 @@ resip::operator<<(EncodeStream& strm, const resip::TransactionState& state)
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  * DAMAGE.
- * 
+ *
  * ====================================================================
- * 
+ *
  * This software consists of voluntary contributions made by Vovida
  * Networks, Inc. and many individuals on behalf of Vovida Networks,
  * Inc.  For more information on Vovida Networks, Inc., please see
diff --git resip/stack/TransactionState.hxx resip/stack/TransactionState.hxx
index cdf46d2..5d09718 100644
--- resip/stack/TransactionState.hxx
+++ resip/stack/TransactionState.hxx
@@ -31,13 +31,15 @@ class TransactionState : public DnsHandler
    public:
       RESIP_HeapCount(TransactionState);
       static void process(TransactionController& controller,
-                           TransactionMessage* message); 
+                           TransactionMessage* message);
       static void processTimer(TransactionController& controller,
-                                 TimerMessage* timer); 
+                                 TimerMessage* timer);
       ~TransactionState();
-     
+
+      /// Reimplemented from DnsHandler.
+      virtual bool isBlackListException( const Tuple& t );
    private:
-      typedef enum 
+      typedef enum
       {
          ClientNonInvite,
          ClientInvite,
@@ -47,8 +49,8 @@ class TransactionState : public DnsHandler
          ServerStale,
          Stateless  // may not be needed
       } Machine;
-      
-      typedef enum 
+
+      typedef enum
       {
          Calling,
          Trying,
@@ -59,18 +61,18 @@ class TransactionState : public DnsHandler
          Bogus
       } State;
 
-      TransactionState(TransactionController& controller, 
-                       Machine m, 
-                       State s, 
-                       const Data& tid, 
+      TransactionState(TransactionController& controller,
+                       Machine m,
+                       State s,
+                       const Data& tid,
                        MethodTypes method,
                        const Data& methodText,
                        TransactionUser* tu=0);
-      
+
       void rewriteRequest(const Uri& rewrite);
       void handle(DnsResult*);
       void handleSync(DnsResult*);
-      
+
       void processStateless(TransactionMessage* msg);
       void processClientNonInvite(TransactionMessage* msg);
       void processClientInvite(TransactionMessage* msg);
@@ -81,10 +83,10 @@ class TransactionState : public DnsHandler
       void processTransportFailure(TransactionMessage* failure);
       void processNoDnsResults();
       void processReliability(TransportType type);
-      
+
       void add(const Data& tid);
       void erase(const Data& tid);
-      
+
       bool isClient() const;
    private:
       bool isRequest(TransactionMessage* msg) const;
@@ -104,8 +106,8 @@ class TransactionState : public DnsHandler
       static void sendToTU(TransactionUser* tu, TransactionController& controller, TransactionMessage* msg);
       void sendCurrentToWire();
       SipMessage* make100(SipMessage* request) const;
-      void terminateClientTransaction(const Data& tid); 
-      void terminateServerTransaction(const Data& tid); 
+      void terminateClientTransaction(const Data& tid);
+      void terminateServerTransaction(const Data& tid);
       const Data& tid(SipMessage* sip) const;
 
       void startServerNonInviteTimerTrying(SipMessage& sip, const Data& tid);
@@ -130,24 +132,24 @@ class TransactionState : public DnsHandler
          mMsgToRetransmit.clear();
       }
 
-      static bool processSipMessageAsNew(resip::SipMessage* sip, 
+      static bool processSipMessageAsNew(resip::SipMessage* sip,
                                          resip::TransactionController& controller,
                                          const resip::Data& tid);
 
       TransactionController& mController;
-      
+
       Machine mMachine;
       State mState;
       bool mIsAbandoned; // TU doesn't care about this transaction anymore.
-      
+
       // Indicates that the message has been sent with a reliable protocol. Set
       // by the TransportSelector
       bool mIsReliable;
 
       // !bwc! sendCurrentToWire() uses these to determine what it should put on
-      // the wire. If mMsgToRetransmit is non-empty, it goes on the wire 
-      // _regardless_ of what mNextTransmission is. If mMsgToRetransmit is 
-      // empty, but mNextTransmission is non-null, sendCurrentToWire() will try 
+      // the wire. If mMsgToRetransmit is non-empty, it goes on the wire
+      // _regardless_ of what mNextTransmission is. If mMsgToRetransmit is
+      // empty, but mNextTransmission is non-null, sendCurrentToWire() will try
       // to send it.
       SipMessage* mNextTransmission;
       SendData mMsgToRetransmit;
@@ -156,8 +158,8 @@ class TransactionState : public DnsHandler
       DnsResult* mDnsResult;
 
       // current selection from the DnsResult. e.g. it is important to send the
-      // CANCEL to exactly the same tuple as the original INVITE went to. 
-      Tuple mTarget; 
+      // CANCEL to exactly the same tuple as the original INVITE went to.
+      Tuple mTarget;
       Tuple mResponseTarget; // used to reply to requests
 
       // used when the DnsResult moves to another transport on failure. Only
@@ -176,11 +178,11 @@ class TransactionState : public DnsHandler
       bool mAckIsValid;
       bool mWaitingForDnsResult;
       TransactionUser* mTransactionUser;
-      TransportFailure::FailureReason mFailureReason;      
+      TransportFailure::FailureReason mFailureReason;
       int mFailureSubCode;
 
       static UInt32 StatelessIdCounter;
-      
+
       friend EncodeStream& operator<<(EncodeStream& strm, const TransactionState& state);
       friend class TransactionController;
 };
@@ -191,22 +193,22 @@ class TransactionState : public DnsHandler
 #endif
 
 /* ====================================================================
- * The Vovida Software License, Version 1.0 
- * 
+ * The Vovida Software License, Version 1.0
+ *
  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 
+ *
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
- * 
+ *
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in
  *    the documentation and/or other materials provided with the
  *    distribution.
- * 
+ *
  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
  *    and "Vovida Open Communication Application Library (VOCAL)" must
  *    not be used to endorse or promote products derived from this
@@ -216,7 +218,7 @@ class TransactionState : public DnsHandler
  * 4. Products derived from this software may not be called "VOCAL", nor
  *    may "VOCAL" appear in their name, without prior written
  *    permission of Vovida Networks, Inc.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
@@ -230,9 +232,9 @@ class TransactionState : public DnsHandler
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  * DAMAGE.
- * 
+ *
  * ====================================================================
- * 
+ *
  * This software consists of voluntary contributions made by Vovida
  * Networks, Inc. and many individuals on behalf of Vovida Networks,
  * Inc.  For more information on Vovida Networks, Inc., please see
diff --git resip/stack/TransactionUser.hxx resip/stack/TransactionUser.hxx
index e40a2bf..8d6017f 100644
--- resip/stack/TransactionUser.hxx
+++ resip/stack/TransactionUser.hxx
@@ -1,5 +1,5 @@
 #if !defined(RESIP_TU_HXX)
-#define RESIP_TU_HXX 
+#define RESIP_TU_HXX
 
 #include <iosfwd>
 #include <set>
@@ -15,7 +15,7 @@ namespace resip
 class SipMessage;
 
 /**
-   @brief The base-class for an RFC 3261 Transaction User. This is the 
+   @brief The base-class for an RFC 3261 Transaction User. This is the
       "app-layer".
 
       Subclasses of TransactionUser are expected to do the following things:
@@ -23,24 +23,24 @@ class SipMessage;
          - Regularly pull messages out of mFifo, and process them.
             - Particularly, every received SIP request MUST be responded to, or
                the stack will leak transactions.
-         - Before the TransactionUser is destroyed, it should ensure that it has 
-            been unregistered from the stack using 
-            SipStack::unregisterTransactionUser(), and gotten a confirmation in 
+         - Before the TransactionUser is destroyed, it should ensure that it has
+            been unregistered from the stack using
+            SipStack::unregisterTransactionUser(), and gotten a confirmation in
             the form of a TransactionUserMessage.
 
-      There is also a collection of things you can do to customize how the stack 
+      There is also a collection of things you can do to customize how the stack
       interacts with your TransactionUser:
          - If you wish to restrict the types of SIP traffic your TransactionUser
-            will receive from the stack, you can do so by setting the 
-            MessageFilterRuleList, either in the constructor, or with 
+            will receive from the stack, you can do so by setting the
+            MessageFilterRuleList, either in the constructor, or with
             setMessageFilterRuleList() (see MessageFilterRule for more)
-            - If you need more fine-grained control over what SIP messages your 
-               TransactionUser is willing/able to handle, you can override 
+            - If you need more fine-grained control over what SIP messages your
+               TransactionUser is willing/able to handle, you can override
                TransactionUser::isForMe().
-         - If you wish your TransactionUser to be notified whenever a 
-            transaction ends, just pass RegisterForTransactionTermination in the 
+         - If you wish your TransactionUser to be notified whenever a
+            transaction ends, just pass RegisterForTransactionTermination in the
             constructor.
-         - If you wish your TransactionUser to be notified when Connections are 
+         - If you wish your TransactionUser to be notified when Connections are
             closed, pass RegisterForConnectionTermination in the constructor.
 
    @ingroup resip_crit
@@ -49,26 +49,32 @@ class TransactionUser
 {
    public:
       /**
-         @brief Posts a Message to this TransactionUser's fifo. Ownership of msg 
+         @brief Check provided Tuple if it must be gere/black listed or not.
+         @param t Target.
+      */
+      virtual bool isBlackListException( const Tuple& t ){ return false; }
+
+      /**
+         @brief Posts a Message to this TransactionUser's fifo. Ownership of msg
             is taken.
          @param msg The Message to add to mFifo. (This takes ownership of msg)
       */
       void post(Message* msg);
 
       /**
-         @brief Returns true iff domain matches one of the domains that this 
+         @brief Returns true iff domain matches one of the domains that this
             TransactionUser is responsible for. (added with addDomain).
          @param domain The domain name to check.
          @return True iff this TransactionUser is responsible for domain.
-         @note The comparison performed is case-sensitive; make sure you 
+         @note The comparison performed is case-sensitive; make sure you
             lower-case everything you put in here.
       */
       bool isMyDomain(const Data& domain) const;
 
       /**
-         @brief Adds a domain to the set of domains that this TransactionUser is 
+         @brief Adds a domain to the set of domains that this TransactionUser is
             responsible for.
-         @note The comparison performed is case-sensitive; make sure you 
+         @note The comparison performed is case-sensitive; make sure you
             lower-case everything you put in here.
          @todo Make this case-insensitive.
       */
@@ -81,7 +87,7 @@ class TransactionUser
       virtual const Data& name() const=0;
 
       /**
-         @brief Encodes the name of this TransactionUser (as specified by 
+         @brief Encodes the name of this TransactionUser (as specified by
             name()), and the current depth of its fifo.
          @param strm The ostream to encode to.
          @return strm
@@ -90,11 +96,11 @@ class TransactionUser
 
       /**
          @brief Sets this TransactionUser's MessageFilterRuleList.
-         
-         This tells the stack which SIP messages this TransactionUser is 
-         interested in, and which ones it is not. This allows multiple 
+
+         This tells the stack which SIP messages this TransactionUser is
+         interested in, and which ones it is not. This allows multiple
          TransactionUsers to run on top of the same SipStack.
-         
+
          @param rules The MessageFilterRuleList to use.
          @see MessageFilterRule
       */
@@ -102,14 +108,14 @@ class TransactionUser
 
       /**
          @internal
-         @brief Returns true iff this TransactionUser should be notified when 
+         @brief Returns true iff this TransactionUser should be notified when
             transactions end.
       */
       bool isRegisteredForTransactionTermination() const;
 
       /**
          @internal
-         @brief Returns true iff this TransactionUser should be notified when 
+         @brief Returns true iff this TransactionUser should be notified when
             connections close.
       */
       bool isRegisteredForConnectionTermination() const;
@@ -123,7 +129,7 @@ class TransactionUser
          }
          return CongestionManager::NORMAL;
       }
-      
+
       virtual void setCongestionManager(CongestionManager* manager)
       {
          if(mCongestionManager)
@@ -136,12 +142,12 @@ class TransactionUser
             mCongestionManager->registerFifo(&mFifo);
          }
       }
-      
+
       virtual UInt16 getExpectedWait() const
       {
          return (UInt16)mFifo.expectedWaitTimeMilliSec();
       }
-      
+
       // .bwc. This specifies whether the TU can cope with dropped responses
       // (due to congestion). Some TUs may need responses to clean up state,
       // while others may rely on TransactionTerminated messages. Those that
@@ -149,37 +155,37 @@ class TransactionUser
       // here, meaning that in dire congestion situations, the stack will drop
       // responses bound for the TU.
       virtual bool responsesMandatory() const {return true;}
-      
+
    protected:
-      enum TransactionTermination 
+      enum TransactionTermination
       {
          RegisterForTransactionTermination,
          DoNotRegisterForTransactionTermination
       };
 
-      enum ConnectionTermination 
+      enum ConnectionTermination
       {
          RegisterForConnectionTermination,
          DoNotRegisterForConnectionTermination
       };
 
-      enum KeepAlivePongs 
+      enum KeepAlivePongs
       {
          RegisterForKeepAlivePongs,
          DoNotRegisterForKeepAlivePongs
       };
 
       /**
-         @brief Constructor that specifies whether this TransactionUser needs to 
-            hear about the completion of transactions, and the closing of 
+         @brief Constructor that specifies whether this TransactionUser needs to
+            hear about the completion of transactions, and the closing of
             connections.
-         @param t Whether or not the TransactionUser should be informed when 
+         @param t Whether or not the TransactionUser should be informed when
             transactions end (disabled by default).
-         @param c Whether or not the TransactionUser should be informed when 
+         @param c Whether or not the TransactionUser should be informed when
             connections close (disabled by default).
-         @note The default MessageFilterRuleList used will accept all SIP 
+         @note The default MessageFilterRuleList used will accept all SIP
             requests with either sip: or sips: in the Request-Uri.
-         @note This is protected to ensure than no-one constructs the 
+         @note This is protected to ensure than no-one constructs the
             base-class. (Subclasses call this in their constructor)
       */
       TransactionUser(TransactionTermination t=DoNotRegisterForTransactionTermination,
@@ -187,18 +193,18 @@ class TransactionUser
                       KeepAlivePongs k=DoNotRegisterForKeepAlivePongs);
 
       /**
-         @brief Constructor that specifies the MessageFilterRuleList, whether 
-            this TransactionUser needs to hear about the completion of 
+         @brief Constructor that specifies the MessageFilterRuleList, whether
+            this TransactionUser needs to hear about the completion of
             transactions, and the closing of connections.
          @param rules The MessageFilterRuleList to use. (A copy is made)
-         @param t Whether or not the TransactionUser should be informed when 
+         @param t Whether or not the TransactionUser should be informed when
             transactions end (disabled by default).
-         @param c Whether or not the TransactionUser should be informed when 
+         @param c Whether or not the TransactionUser should be informed when
             connections close (disabled by default).
-         @note This is protected to ensure than no-one constructs the 
+         @note This is protected to ensure than no-one constructs the
             base-class. (Subclasses call this in their constructor)
       */
-      TransactionUser(MessageFilterRuleList &rules, 
+      TransactionUser(MessageFilterRuleList &rules,
                       TransactionTermination t=DoNotRegisterForTransactionTermination,
                       ConnectionTermination c=DoNotRegisterForConnectionTermination,
                       KeepAlivePongs k=DoNotRegisterForKeepAlivePongs);
@@ -209,19 +215,19 @@ class TransactionUser
          @brief Returns true iff this TransactionUser should process msg.
          @param msg The SipMessage we received.
          @return True iff this TransactionUser should process msg.
-         @note By default, this uses the MessageFilterRuleList. It can be 
+         @note By default, this uses the MessageFilterRuleList. It can be
             overridden for more flexibility.
       */
       virtual bool isForMe(const SipMessage& msg) const;
 
       /**
-         @brief This TransactionUser's fifo. All communication with the 
+         @brief This TransactionUser's fifo. All communication with the
             TransactionUser goes through here.
       */
       TimeLimitFifo<Message> mFifo;
       CongestionManager* mCongestionManager;
 
-   private:      
+   private:
       void postToTransactionUser(Message* msg, TimeLimitFifo<Message>::DepthUsage usage);
       unsigned int size() const;
       bool wouldAccept(TimeLimitFifo<Message>::DepthUsage usage) const;
@@ -233,10 +239,10 @@ class TransactionUser
       bool mRegisteredForTransactionTermination;
       bool mRegisteredForConnectionTermination;
       bool mRegisteredForKeepAlivePongs;
-      friend class TuSelector;      
+      friend class TuSelector;
 };
 
-EncodeStream& 
+EncodeStream&
 operator<<(EncodeStream& strm, const TransactionUser& tu);
 
 }
@@ -244,22 +250,22 @@ operator<<(EncodeStream& strm, const TransactionUser& tu);
 #endif
 
 /* ====================================================================
- * The Vovida Software License, Version 1.0 
- * 
+ * The Vovida Software License, Version 1.0
+ *
  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 
+ *
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
- * 
+ *
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in
  *    the documentation and/or other materials provided with the
  *    distribution.
- * 
+ *
  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
  *    and "Vovida Open Communication Application Library (VOCAL)" must
  *    not be used to endorse or promote products derived from this
@@ -269,7 +275,7 @@ operator<<(EncodeStream& strm, const TransactionUser& tu);
  * 4. Products derived from this software may not be called "VOCAL", nor
  *    may "VOCAL" appear in their name, without prior written
  *    permission of Vovida Networks, Inc.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
@@ -283,9 +289,9 @@ operator<<(EncodeStream& strm, const TransactionUser& tu);
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  * DAMAGE.
- * 
+ *
  * ====================================================================
- * 
+ *
  * This software consists of voluntary contributions made by Vovida
  * Networks, Inc. and many individuals on behalf of Vovida Networks,
  * Inc.  For more information on Vovida Networks, Inc., please see
diff --git rutil/dns/DnsHandler.hxx rutil/dns/DnsHandler.hxx
index 61135f7..45fa648 100644
--- rutil/dns/DnsHandler.hxx
+++ rutil/dns/DnsHandler.hxx
@@ -7,39 +7,43 @@ namespace resip
 class DnsResult;
 class TransactionState;
 class Uri;
+class Tuple;
 
 class DnsHandler
 {
    public:
       virtual ~DnsHandler()=0;
-      
+
       // call when dns entries are available (or nothing found)
       // this may be called synchronously with the call to lookup
       virtual void handle(DnsResult* result)=0;
       virtual void rewriteRequest(const Uri& uri)=0;
+
+      /// Check if given Tuple target ca/can't be penalized.
+      virtual bool isBlackListException( const Tuple& ){ return false; }
 };
- 
+
 }
 
 
 #endif
 /* ====================================================================
- * The Vovida Software License, Version 1.0 
- * 
+ * The Vovida Software License, Version 1.0
+ *
  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
- * 
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 
+ *
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
- * 
+ *
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in
  *    the documentation and/or other materials provided with the
  *    distribution.
- * 
+ *
  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
  *    and "Vovida Open Communication Application Library (VOCAL)" must
  *    not be used to endorse or promote products derived from this
@@ -49,7 +53,7 @@ class DnsHandler
  * 4. Products derived from this software may not be called "VOCAL", nor
  *    may "VOCAL" appear in their name, without prior written
  *    permission of Vovida Networks, Inc.
- * 
+ *
  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
@@ -63,9 +67,9 @@ class DnsHandler
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
  * DAMAGE.
- * 
+ *
  * ====================================================================
- * 
+ *
  * This software consists of voluntary contributions made by Vovida
  * Networks, Inc. and many individuals on behalf of Vovida Networks,
  * Inc.  For more information on Vovida Networks, Inc., please see