natfw/natfwstunturnclient/src/cstuntransaction.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/natfw/natfwstunturnclient/src/cstuntransaction.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,872 @@
+/*
+* Copyright (c) 2006-2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:    
+*
+*/
+
+
+
+
+#include "natfwunsaflog.h"
+#include "cnatfwunsafudpsender.h"
+#include "natfwunsafbindingrequest.h"
+#include "natfwunsaferrorcodeattribute.h"
+#include "natfwunsafunknownattributesattribute.h"
+#include "natfwunsafmessageintegrityattribute.h"
+#include "stunassert.h"
+#include "stunutils.h"
+#include "mstuntransactionobserver.h"
+#include "cstuntransaction.h"
+#include "ttransactioncleanup.h"
+#include "stunturnclientlogs.h"
+#include "tstuncallbackinfo.h"
+
+// ======== MEMBER FUNCTIONS ========
+
+const TInt KInitCompareValue = 1;
+
+// Divide factor from uSecs to mSecs
+const TInt KDivideFactor = 1000;
+
+const TInt KWaitingTime = 1600; // rfc3489bis-06#section-7.1
+
+const TInt KMaxTCPWaitingTime = 7900; // rfc3489bis-06#section-7.1
+
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::NewL
+// ---------------------------------------------------------------------------
+//
+CSTUNTransaction* CSTUNTransaction::NewL( CNATFWUNSAFMessage& aRequest,
+                                          const TInetAddr& aAddress,
+                                          const TDesC8& aSharedSecret,
+                                          RSocket& aSocket,
+                                          CDeltaTimer& aTimer,
+                                          TInt aRetransmitInterval,
+                                          MSTUNTransactionObserver& aObserver,
+                                          const TDesC8& aProtocol,
+                                          TTransportProtocol aTransportProtocol )
+    {
+    __ASSERT_ALWAYS( !aAddress.IsUnspecified(), User::Leave( KErrArgument ) );
+
+    CSTUNTransaction* self =
+        new ( ELeave ) CSTUNTransaction( aRequest,
+                                         aAddress,
+                                         aSharedSecret,
+                                         aTimer,
+                                         aRetransmitInterval,
+                                         aObserver,
+                                         aTransportProtocol );
+    CleanupStack::PushL( self );
+    self->ConstructL( aSocket, aProtocol );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::NewL - overloaded
+// ---------------------------------------------------------------------------
+//
+CSTUNTransaction* CSTUNTransaction::NewL( CNATFWUNSAFMessage& aRequest,
+                                          const TInetAddr& aAddress,
+                                          const TDesC8& aSharedSecret,
+                                          TUint aStreamId,
+                                          TUint aConnectionId,
+                                          CDeltaTimer& aTimer,
+                                          TInt aRetransmitInterval,
+                                          MSTUNTransactionObserver& aObserver,
+                                          const TDesC8& aProtocol,
+                                          MNcmConnectionMultiplexer& aMux,
+                                          TTransportProtocol aTransportProtocol,
+                                          TBool aUseFingerprint,
+                                          const TInetAddr& aDestAddr )
+    {
+    __ASSERT_ALWAYS( !aAddress.IsUnspecified(), User::Leave( KErrArgument ) );
+
+    CSTUNTransaction* self =
+        new ( ELeave ) CSTUNTransaction( aRequest,
+                                         aAddress,
+                                         aSharedSecret,
+                                         aStreamId,
+                                         aConnectionId,
+                                         aTimer,
+                                         aRetransmitInterval,
+                                         aObserver,
+                                         aDestAddr,
+                                         aTransportProtocol,
+                                         aUseFingerprint );
+    CleanupStack::PushL( self );
+    self->ConstructL( aProtocol, aMux );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::CSTUNTransaction
+// ---------------------------------------------------------------------------
+//
+CSTUNTransaction::CSTUNTransaction( CNATFWUNSAFMessage& aRequest,
+                                    const TInetAddr& aAddress,
+                                    const TDesC8& aSharedSecret,
+                                    CDeltaTimer& aTimer,
+                                    TInt aRetransmitInterval,
+                                    MSTUNTransactionObserver& aObserver,
+                                    TTransportProtocol aTransportProtocol ) :
+    CSTUNTimerUser( aTimer ),
+    iObserver( aObserver ),
+    iRequest( aRequest ),
+    iAddress( aAddress ),
+    iSharedSecret( aSharedSecret ),
+    iInitialRetransmitInterval( aRetransmitInterval ),
+    iRetransmit( ETrue ),
+    iTransportProtocol( aTransportProtocol ),
+    iRetransmitCompareValue( KInitCompareValue )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::CSTUNTransaction - overloaded
+// ---------------------------------------------------------------------------
+//
+CSTUNTransaction::CSTUNTransaction( CNATFWUNSAFMessage& aRequest,
+                                    const TInetAddr& aAddress,
+                                    const TDesC8& aSharedSecret,
+                                    TUint aStreamId,
+                                    TUint aConnectionId,
+                                    CDeltaTimer& aTimer,
+                                    TInt aRetransmitInterval,
+                                    MSTUNTransactionObserver& aObserver,
+                                    const TInetAddr& aDestAddr,
+                                    TTransportProtocol aTransportProtocol,
+                                    TBool aUseFingerprint ) :
+    CSTUNTimerUser( aTimer ),
+    iObserver( aObserver ),
+    iRequest( aRequest ),
+    iAddress( aAddress ),
+    iSharedSecret( aSharedSecret ),
+    iInitialRetransmitInterval( aRetransmitInterval ),
+    iRetransmit( ETrue ),
+    iStreamId( aStreamId ),
+    iSubstreamId( aConnectionId ),
+    iDestAddr( aDestAddr ),
+    iTransportProtocol( aTransportProtocol ),
+    iRetransmitCompareValue( KInitCompareValue ),
+    iUseFingerprint( aUseFingerprint )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::CSTUNTransaction
+// Dummy implementation. Default constructor is declared private and not used.
+// ---------------------------------------------------------------------------
+//
+CSTUNTransaction::CSTUNTransaction() :
+    CSTUNTimerUser( *( CDeltaTimer* )0x1 ),
+    iObserver( *( MSTUNTransactionObserver* )0x1 ),
+    iRequest( *( CNATFWUNSAFMessage* )0x1 ),
+    iAddress( *( TInetAddr* )0x1 ),
+    iSharedSecret( KNullDesC8 )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::CSTUNTransaction
+// Dummy implementation, as copy constructor is declared private and not used.
+// ---------------------------------------------------------------------------
+//
+CSTUNTransaction::CSTUNTransaction( const CSTUNTransaction& aTransaction ) :
+    CSTUNTimerUser( *( CDeltaTimer* )0x1 ),
+    iObserver( aTransaction.iObserver ),
+    iRequest( aTransaction.iRequest ),
+    iAddress( aTransaction.iAddress ),
+    iSharedSecret( aTransaction.iSharedSecret )
+    {
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CSTUNTransaction::ConstructL( RSocket& aSocket, const TDesC8& aProtocol )
+    {
+    __STUNTURNCLIENT( "CSTUNTransaction::ConstructL with sender" )
+    CheckProtocolL( aProtocol );
+    iSender = CNATFWUNSAFUdpSender::NewL( aSocket, *this );
+    SendRequestL();
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::ConstructL
+// ---------------------------------------------------------------------------
+//
+void CSTUNTransaction::ConstructL( const TDesC8& aProtocol, 
+    MNcmConnectionMultiplexer& aMux  )
+    {
+    __STUNTURNCLIENT( "CSTUNTransaction::ConstructL with mediaconsender" )
+    CheckProtocolL( aProtocol );
+    iMediaConSender = CNATFWUNSAFMediaConnSender::NewL( aMux );
+    SendRequestL();
+    }
+      
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::~CSTUNTransaction
+// ---------------------------------------------------------------------------
+//
+CSTUNTransaction::~CSTUNTransaction()
+    {
+    __STUNTURNCLIENT( "CSTUNTransaction::~CSTUNTransaction IN" )
+    
+    if ( iMediaConSender )
+        {
+        iMediaConSender->Cancel( iStreamId, iSubstreamId, this );
+        }
+    
+    delete iMediaConSender;
+    delete iSender;
+    delete iUnknownAttr;
+    delete iProtocol;
+    
+    __STUNTURNCLIENT( "CSTUNTransaction::~CSTUNTransaction OUT" )
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::NATFWUNSAFUdpMessageSentL
+// ---------------------------------------------------------------------------
+//
+void CSTUNTransaction::UNSAFUdpMessageSentL()
+    {
+    __STUNTURNCLIENT( "CSTUNTransaction::UNSAFUdpMessageSentL" )
+    __TEST_INVARIANT;
+    
+    if ( !iTerminated )
+        {
+        ++iSendCount;
+        
+        if ( iRetransmit )
+            {
+            if ( ETcpProtocol == iTransportProtocol )
+                {
+                StartTimer( KMaxTCPWaitingTime );
+                }
+            else
+                {                       
+                iSendTime.HomeTime();
+                StartTimer( RetransmitInterval() );
+                }
+            }
+        }
+
+    __TEST_INVARIANT;
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::NATFWUNSAFUdpMessageFailure
+// ---------------------------------------------------------------------------
+//
+void CSTUNTransaction::UNSAFUdpMessageFailure( TInt aError )
+    {
+    __STUNTURNCLIENT_INT1( "\
+    CSTUNTransaction::UNSAFUdpMessageFailure, error=", aError )
+    __TEST_INVARIANT;
+    __STUN_ASSERT_RETURN( aError != KErrNone, KErrArgument );
+
+    if ( !iTerminated )
+        {
+        Terminate( aError );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::MessageSent
+// ---------------------------------------------------------------------------
+//
+void CSTUNTransaction::MessageSent()
+    {
+    iRequestPending = EFalse;
+    
+    TRAP_IGNORE( UNSAFUdpMessageSentL() );
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::MessageSentFailure
+// ---------------------------------------------------------------------------
+// 
+void CSTUNTransaction::MessageSentFailure( TInt aError )
+    {
+    __STUNTURNCLIENT_INT1( "\
+    CSTUNTransaction::MessageSentFailure, error=", aError )
+    iRequestPending = EFalse;
+    UNSAFUdpMessageFailure( aError );
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::SendRequestL
+// -----------------------------------------------------------------------------
+//
+void CSTUNTransaction::SendRequestL()
+    {
+    __STUNTURNCLIENT( "CSTUNTransaction::SendRequestL" )
+    if ( iMediaConSender )
+        {
+        __STUNTURNCLIENT( "CSTUNTransaction::SendRequestL with mediaconsender" )
+        if ( iDestAddr.IsUnspecified() )
+            {
+            iMediaConSender->SendL( iStreamId, 
+                iSubstreamId, iRequest, iSharedSecret, this, iUseFingerprint );
+            iRequestPending = ETrue;
+            }
+        else
+            {
+            iMediaConSender->SendL( iStreamId, 
+                                    iSubstreamId, iRequest, iSharedSecret, 
+                                    iDestAddr, this, iUseFingerprint );
+            
+            iRequestPending = ETrue;
+            }
+        }
+    else if ( iSender )
+        {
+        __STUNTURNCLIENT( "CSTUNTransaction::SendRequestL with original sender" )
+        iSender->SendL( iAddress, iRequest, iSharedSecret );
+        }
+    else
+        {
+        User::Leave( KErrNotReady );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::RetransmitRequestL
+// -----------------------------------------------------------------------------
+//
+void CSTUNTransaction::RetransmitRequestL()
+    {
+    __STUNTURNCLIENT_INT1( "\
+    CSTUNTransaction::RetransmitRequestL, sendcount= ",iSendCount )
+    if ( iSendCount < KMaxRequestSentCount )
+        {
+        if ( !iDisableSending )
+            {
+            SendRequestL();
+            }
+        else
+            {
+            iSendTime.HomeTime();
+            StartTimer( RetransmitInterval() );
+            }
+        }
+    else
+        {
+        Terminate( KErrTimedOut );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::ReceiveL
+// Also an ignored response stops retransmission.
+// ---------------------------------------------------------------------------
+//
+void CSTUNTransaction::ReceiveL( CNATFWUNSAFMessage& aResponse,
+                                 const TDesC8& aByteStream )
+    {
+    __TEST_INVARIANT;
+    __STUN_ASSERT_L( 
+        aResponse.Type() == CNATFWUNSAFMessage::EBindingResponse ||
+        aResponse.Type() == CNATFWUNSAFMessage::EBindingErrorResponse ||
+        aResponse.Type() == CNATFWUNSAFMessage::EAllocateResponse ||
+        aResponse.Type() == CNATFWUNSAFMessage::EAllocateErrorResponse ||
+        aResponse.Type() == CNATFWUNSAFMessage::EConnectResponse ||
+        aResponse.Type() == CNATFWUNSAFMessage::EConnectErrorResponse ||
+        aResponse.Type() ==
+            CNATFWUNSAFMessage::ESetActiveDestinationResponse ||
+        aResponse.Type() ==
+            CNATFWUNSAFMessage::ESetActiveDestinationErrorResponse,
+        KErrArgument );
+    
+    if ( !iTerminated )
+        {
+        iRetransmit = EFalse;
+        StopTimer();
+        
+        if ( ShouldIgnoreResponse( aResponse ) )
+            {
+            StartTimer( ComputeWaitDuration() );
+            }
+        else
+            {
+            if ( EUdpProtocol == iTransportProtocol )
+                {
+                MeasureNewRTTSample();
+                }
+            
+            TTransactionCleanup taCleanup( *this );
+            CleanupStack::PushL( taCleanup.CleanupItem() );
+
+            TInt status = ProcessResponseL( aResponse, aByteStream );
+
+            CleanupStack::Pop(); //cleanupItem
+            Terminate( status );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::ShouldIgnoreResponse
+// 1xx-3xx response stops retransmissions, but doesn't terminate transaction.
+// -----------------------------------------------------------------------------
+//
+TBool
+CSTUNTransaction::ShouldIgnoreResponse( const CNATFWUNSAFMessage& aResponse ) const
+    {
+    __TEST_INVARIANT;
+
+    TInt responseCode = GetResponseCode( aResponse );
+    return !aResponse.Validate() ||
+           aResponse.HasUnknownMandatoryAttributes() ||
+           ( responseCode >= E1XX && responseCode < E4XX );
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::ProcessResponseL
+// -----------------------------------------------------------------------------
+//
+TInt CSTUNTransaction::ProcessResponseL( CNATFWUNSAFMessage& aResponse,
+                                         const TDesC8& aByteStream )
+    {
+    __STUNTURNCLIENT( "CSTUNTransaction::ProcessResponseL" )
+    __TEST_INVARIANT;
+                     
+    TInt status = KErrNone;
+    
+    // binding response ( stun functionality )
+    if ( aResponse.Type() == CNATFWUNSAFMessage::EBindingResponse )
+        {
+        status = CheckIntegrityL( aResponse, aByteStream );
+        if ( KErrNone == status )
+            {
+            STUNUtils::GetMappedAddress( aResponse, iMappedAddress );
+            STUNUtils::GetXorMappedAddressL( aResponse, iXorMappedAddress );
+            }
+        }
+    
+    // allocate response ( stun relay functionality )
+    else if ( aResponse.Type() == CNATFWUNSAFMessage::EAllocateResponse )
+        {
+        status = CheckIntegrityL( aResponse, aByteStream );
+        if ( KErrNone == status )
+            {
+            // get server relay address
+            STUNUtils::GetRelayAddressL( aResponse, iRelayAddress );
+            // get server reflexive address
+            STUNUtils::GetXorMappedAddressL( aResponse, iXorMappedAddress );
+            }
+        }
+    
+    // Connect Response ( stun relay TCP functionality )
+    else if ( aResponse.Type() == 
+        CNATFWUNSAFMessage::EConnectResponse )
+        {
+        status = CheckIntegrityL( aResponse, aByteStream );
+        }
+    
+    // Active Destination Response ( stun relay functionality )
+    else if ( aResponse.Type() == 
+        CNATFWUNSAFMessage::ESetActiveDestinationResponse )
+        {
+        __STUNTURNCLIENT( "do msg integrity check for active destination response" )
+        status = CheckIntegrityL( aResponse, aByteStream );
+        if ( KErrNone != status )
+            {
+            __STUNTURNCLIENT_INT1( "msg integrity check for active\
+            destination response FAILED - BUT IGNORE IT - SERVER MISBEHAVIOR DETECTED", status )
+            status = KErrNone; 
+            }
+            
+        if ( KErrNone == status )
+            {
+            // notify stun relay implementation
+            STUNUtils::GetTimerValueL( aResponse, iTimerValue );
+            }
+        }
+        
+    else
+        {
+        status = GetResponseCode( aResponse );
+        if ( E4XX > status )
+            {
+            //Invalid Binding Error Response received
+            status = KErrCorrupt;
+            }            
+        if ( status == E420UnknownAttributes )
+            {
+            __STUN_ASSERT_L( !iUnknownAttr, KErrAlreadyExists );
+            iUnknownAttr = static_cast<CNATFWUNSAFUnknownAttributesAttribute*>(
+                aResponse.Attribute(
+                    CNATFWUNSAFAttribute::EUnknownAttributes ) );
+            aResponse.DetachAttribute( iUnknownAttr );
+            }
+        }
+
+    __TEST_INVARIANT;
+    __STUNTURNCLIENT_INT1( "CSTUNTransaction::ProcessResponseL end, errorcode/status:", status )
+    return status;
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::CheckIntegrityL
+// MESSAGE-INTEGRITY is in the encoded message, not in iRequest. If iRequest has
+// a USERNAME, then also a MESSAGE-INTEGRITY was sent in the Binding Request.
+// -----------------------------------------------------------------------------
+//
+TInt CSTUNTransaction::CheckIntegrityL( const CNATFWUNSAFMessage& aResponse,
+                                         const TDesC8& aByteStream )
+    {
+    __TEST_INVARIANT;
+    __STUN_ASSERT_L( aResponse.Type() == CNATFWUNSAFMessage::EBindingResponse ||
+                     aResponse.Type() == CNATFWUNSAFMessage::EAllocateResponse ||
+                     aResponse.Type() == CNATFWUNSAFMessage::EConnectResponse ||
+                     aResponse.Type() == 
+                        CNATFWUNSAFMessage::ESetActiveDestinationResponse,
+                     KErrArgument );
+
+    if ( !iRequest.Attribute( CNATFWUNSAFAttribute::EUsername ) )
+        {
+        return KErrNone;
+        }
+
+    if ( aResponse.HasAttribute( CNATFWUNSAFAttribute::EMessageIntegrity ) )
+        {
+        if ( static_cast<CNATFWUNSAFMessageIntegrityAttribute*>(
+                aResponse.Attribute( CNATFWUNSAFAttribute::EMessageIntegrity ) )->
+                    CheckMessageIntegrityL( aByteStream, iSharedSecret ) )
+            {
+            return KErrNone;
+            }
+
+        //If XOR-ONLY was already sent, maybe server doesn't support it.
+        if ( CheckForNatOverwriteL( aResponse ) &&
+             !iRequest.Attribute( CNATFWUNSAFAttribute::EXorOnly ) )
+            {
+            return ERetryAfterAddingXorOnly;
+            }
+        }
+
+    return KErrCorrupt;
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::CheckForNatOverwriteL
+// Be compatible with old STUN servers that don't understand XOR-MAPPED-ADDRESS
+// or XOR-ONLY. Don't treat XOR-MAPPED-ADDRESS as mandatory in Binding Response.
+// -----------------------------------------------------------------------------
+//
+TBool CSTUNTransaction::CheckForNatOverwriteL( const CNATFWUNSAFMessage& aResponse )
+    {
+    __TEST_INVARIANT;    
+    __STUN_ASSERT_L( aResponse.Type() == CNATFWUNSAFMessage::EBindingResponse ||
+                     aResponse.Type() == CNATFWUNSAFMessage::EAllocateResponse,
+                     KErrArgument );
+    TInetAddr mappedAddr;
+    TInetAddr xorMappedAddr;
+    return STUNUtils::GetMappedAddress( aResponse, mappedAddr ) &&
+           STUNUtils::GetXorMappedAddressL( aResponse, xorMappedAddr ) &&
+           !mappedAddr.CmpAddr( xorMappedAddr );
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::GetResponseCode
+// -----------------------------------------------------------------------------
+//
+TInt CSTUNTransaction::
+    GetResponseCode( const CNATFWUNSAFMessage& aResponse ) const
+    {
+    __TEST_INVARIANT;
+    if ( aResponse.Type() == CNATFWUNSAFMessage::EBindingErrorResponse ||
+         aResponse.Type() == CNATFWUNSAFMessage::EAllocateErrorResponse ||
+         aResponse.Type() == CNATFWUNSAFMessage::EConnectErrorResponse ||
+         aResponse.Type() == 
+                CNATFWUNSAFMessage::ESetActiveDestinationErrorResponse )
+        {
+        CNATFWUNSAFErrorCodeAttribute* errorCode =
+            static_cast<CNATFWUNSAFErrorCodeAttribute*>
+            ( aResponse.Attribute( CNATFWUNSAFAttribute::EErrorCode ) );
+        
+        if ( errorCode )
+            {
+            return errorCode->ResponseCode();
+            }
+        }
+    return KErrNotFound;
+    }
+
+// ---------------------------------------------------------------------------
+// CSTUNTransaction::Terminate
+// Don't use invariant at the end of Terminate nor elsewhere after calling it,
+// as binding deletes this transaction.
+// If PublicAddressObtainedL leaves, call TransactionError.
+// ---------------------------------------------------------------------------
+//
+void CSTUNTransaction::Terminate( TInt aError )
+    {
+    __STUNTURNCLIENT_INT1( "CSTUNTransaction::Terminate, error = ", aError )
+    __TEST_INVARIANT;
+    
+    //Terminate only once
+    __STUN_ASSERT_RETURN( !iTerminated, KErrDied );
+    NATFWUNSAF_INTLOG( "STUNTransaction terminated, reason:", aError )
+
+    iTerminated = ETrue;
+
+    if ( aError == KErrNone )
+        {
+        TInetAddr publicAddr = iXorMappedAddress;
+        if ( publicAddr.IsUnspecified() )
+            {
+            publicAddr = iMappedAddress;
+            }
+        
+        if ( publicAddr.IsUnspecified() )
+            {
+            if ( CNATFWUNSAFMessage::ESetActiveDestinationRequest ==
+                        iRequest.Type() )
+                {
+                TRAP( aError, iObserver.TransactionEventOccurredL( 
+                    TSTUNCallbackInfo::EEventActiveDestinationSet ) );
+                if ( aError )
+                    {
+                    __STUNTURNCLIENT_INT1(
+                        "TransactionEventOccurredL leaves, reason:", aError )
+                    }
+                }
+            else if ( CNATFWUNSAFMessage::EConnectRequest == iRequest.Type() )
+                {
+                TRAP( aError, iObserver.TransactionEventOccurredL( 
+                    TSTUNCallbackInfo::EEventTCPConnectOk ) );
+                if ( aError )
+                    {
+                    __STUNTURNCLIENT_INT1(
+                        "TransactionEventOccurredL leaves, reason:", aError )
+                    }
+                }
+            else
+                {
+                // Server sent invalid Binding Response
+                aError = KErrCorrupt;
+                }
+            }
+        else
+            {
+            if ( !StunRelayUsed() || iRelayAddress.IsUnspecified() )
+                {
+                __STUNTURNCLIENT( "\
+                CSTUNTransaction::Terminate StunRelay NOT Used." )
+                TRAP( aError, iObserver.PublicAddressObtainedL( publicAddr ) );
+                }
+            else
+                {
+                __STUNTURNCLIENT( "\
+                CSTUNTransaction::Terminate StunRelay Used." )
+                TRAP( aError, iObserver.PublicAddressObtainedL( 
+                    publicAddr, iRelayAddress ) );
+                }
+            }
+        }
+        
+    if ( aError )
+        {
+        CNATFWUNSAFUnknownAttributesAttribute* unknownAttr = iUnknownAttr;
+        iUnknownAttr = NULL;
+        iObserver.TransactionError( aError, unknownAttr );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::RetransmitInterval
+// -----------------------------------------------------------------------------
+//
+TInt CSTUNTransaction::RetransmitInterval()
+    {
+    __STUNTURNCLIENT( "CSTUNTransaction::RetransmitInterval" )
+    __TEST_INVARIANT;
+    
+    if ( 0 == iRetransmitInterval )
+        {
+        iRetransmitInterval = iInitialRetransmitInterval;
+        }
+    else if ( KMaxRequestSentCount == iSendCount )
+        {
+        iRetransmitInterval = KWaitingTime;
+        }
+    else
+        {
+        iRetransmitInterval = iRetransmitInterval << 1;
+        }
+
+    __TEST_INVARIANT;
+    return iRetransmitInterval;
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::ComputeWaitDuration
+// -----------------------------------------------------------------------------
+//
+TInt CSTUNTransaction::ComputeWaitDuration()
+    {
+    __STUNTURNCLIENT( "CSTUNTransaction::ComputeWaitDuration" )
+    __TEST_INVARIANT;
+
+    TInt duration( 0 );
+    for ( TInt i = iSendCount; i < KMaxRequestSentCount; ++i )
+        {
+        duration += RetransmitInterval();
+        }
+
+    __TEST_INVARIANT;
+    return duration;
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::TimerExpiredL
+// -----------------------------------------------------------------------------
+//
+void CSTUNTransaction::TimerExpiredL()
+    {
+    __STUNTURNCLIENT( "CSTUNTransaction::TimerExpiredL" )
+    __TEST_INVARIANT;
+
+    if ( iRetransmit && EUdpProtocol == iTransportProtocol )
+        {
+        RetransmitRequestL();
+        }
+    else
+        {
+        Terminate( KErrTimedOut );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::LeaveFromTimerExpired
+// -----------------------------------------------------------------------------
+//
+void CSTUNTransaction::LeaveFromTimerExpired( TInt aError )
+    {
+    __STUNTURNCLIENT_INT1( "\
+    CSTUNTransaction::LeaveFromTimerExpired, error = ", aError )
+    __TEST_INVARIANT;
+    __STUN_ASSERT_RETURN( aError != KErrNone, KErrArgument );
+
+    Terminate( aError );
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::TimerValue
+// -----------------------------------------------------------------------------
+//
+const TUint32& CSTUNTransaction::TimerValue() const
+    {
+    return iTimerValue;
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::CancelRetransmission
+// -----------------------------------------------------------------------------
+//
+void CSTUNTransaction::CancelRetransmission()
+    {
+    iDisableSending = ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::CheckProtocolL
+// -----------------------------------------------------------------------------
+//
+void CSTUNTransaction::CheckProtocolL( const TDesC8& aProtocol )
+    {
+    __STUNTURNCLIENT( "CSTUNTransaction::CheckProtocolL" )
+    delete iProtocol;
+    iProtocol = NULL;
+    
+    if ( aProtocol.Compare( KStun ) )
+        {
+        iProtocol = aProtocol.AllocL();
+        }
+    else if ( aProtocol.Compare( KStunRelay ) )
+        {
+        iProtocol = aProtocol.AllocL();
+        }
+    else
+        {
+        User::Leave( KErrArgument );
+        }
+    }
+    
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::StunRelayUsed
+// -----------------------------------------------------------------------------
+//
+TBool CSTUNTransaction::StunRelayUsed()
+    {
+    __STUNTURNCLIENT( "CSTUNTransaction::StunRelayUsed()" )
+    return !iProtocol->Compare( KStunRelay );
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::MeasureNewRTTSample
+// -----------------------------------------------------------------------------
+//
+void CSTUNTransaction::MeasureNewRTTSample()
+    {
+    TTime curTime;
+    curTime.HomeTime();
+    
+    //Measured RTT ( Round-trip time )
+    TTimeIntervalMicroSeconds time = curTime.MicroSecondsFrom( iSendTime );
+    // change microsecs to millisecs
+    TInt64 rttSample = time.Int64() / TInt64( KDivideFactor );
+    
+    // rfc3489bis-06#section-7.1
+    // As with TCP, the usage of Karn's
+    // algorithm is RECOMMENDED.  When applied to STUN, it means that RTT
+    // estimates SHOULD NOT be computed from STUN transactions which result
+    // in the retransmission of a request.
+
+    TBool retransmitted( EFalse );
+    
+    if ( iRetransmitCompareValue < iSendCount )
+        {
+        retransmitted = ETrue;
+        rttSample = iRetransmitInterval;
+        }
+        
+    iObserver.NewRTTSampleMeasured( rttSample, retransmitted );
+    }
+
+// -----------------------------------------------------------------------------
+// CSTUNTransaction::__DbgTestInvariant
+// -----------------------------------------------------------------------------
+// 
+void CSTUNTransaction::__DbgTestInvariant() const
+    {
+#if defined( _DEBUG )
+    if ( /*!iSender ||*/
+         iAddress.IsUnspecified() ||
+         iSendCount < 0 ||
+         iSendCount > KMaxRequestSentCount ||         
+         iRetransmitInterval < 0 )
+        {
+        __STUNTURNCLIENT( "CSTUNTransaction::__DbgTestInvariant()\
+        stage#1 panic" )
+        User::Invariant();
+        }
+#endif
+    }