natfw/natfwstunserver/src/natfwstunsrvimpl.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/natfw/natfwstunserver/src/natfwstunsrvimpl.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,724 @@
+/*
+* Copyright (c) 2007-2008 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:    Implementation of NAT FW STUN server implementation
+*
+*/
+
+
+
+
+#include <e32def.h>
+#include <es_sock.h>
+#include <in_sock.h>
+
+#include "mncmconnectionmultiplexer.h"
+#include "natfwstunsrvimpl.h"
+#include "natfwcredentials.h"
+#include "natfwstunserverlogs.h"
+#include "natfwunsafbindingerrorresponse.h"
+#include "natfwunsafbindingresponse.h"
+#include "natfwunsaferrorcodeattribute.h"
+#include "natfwunsafusernameattribute.h"
+#include "natfwunsafmessagefactory.h"
+#include "natfwunsafmessageintegrityattribute.h"
+#include "natfwunsafpasswordattribute.h"
+#include "natfwunsafmappedaddressattribute.h"
+#include "natfwunsafusecandidateattribute.h"
+#include "natfwunsafpriorityattribute.h"
+#include "natfwunsafxormappedaddressattribute.h"
+#include "natfwunsafdataindication.h"
+#include "natfwunsafdataattribute.h"
+#include "natfwstunsrvobserver.h"
+#include "natfwunsaficecontrollingattribute.h"
+#include "natfwunsaficecontrolledattribute.h"
+#include "natfwunsaffingerprintattribute.h"
+
+const TInt KErrorCode401        = 401;
+const TInt KErrRoleConflict     = 487;
+const TInt KMaxLength           = 23;
+const TInt KMaxTrackedIdCount   = 16;
+
+_LIT8( KUnauthorized, "Unauthorized" );
+_LIT8( KRoleConflict, "Role Conflict" );
+_LIT8( KColon, ":" );
+
+
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::CNATFWSTUNSrvImpl
+// ---------------------------------------------------------------------------
+//
+CNATFWSTUNSrvImpl::CNATFWSTUNSrvImpl( MNATFWStunSrvObserver& aObserver ) :
+                                      iObserver( aObserver ),
+                                      iFromAddress( KInetAddrNone, 0 ),
+                                      iPeerAddr( KInetAddrNone, 0 ),
+                                      iLocalAddress( KInetAddrNone, 0 )
+    {    
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::NewL
+// ---------------------------------------------------------------------------
+//
+CNATFWSTUNSrvImpl* CNATFWSTUNSrvImpl::NewL( MNATFWStunSrvObserver& aObserver,
+    MNcmConnectionMultiplexer& aMultiplexer )
+    {
+     __STUNSERVER( "CNATFWSTUNSrvImpl::NewL" )
+
+    CNATFWSTUNSrvImpl* self =  new ( ELeave ) CNATFWSTUNSrvImpl( aObserver );
+    CleanupStack::PushL( self );
+    self->ConstructL( aMultiplexer );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CNATFWSTUNSrvImpl::ConstructL( MNcmConnectionMultiplexer& aMultiplexer )
+    {
+     __STUNSERVER( "CNATFWSTUNSrvImpl::ConstructL" )
+    
+    iMultiplexer = &aMultiplexer; 
+    iUsername = KNullDesC8().AllocL();
+    }
+    
+    
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvClientSession::~CNATFWSTUNSrvImpl 
+// ---------------------------------------------------------------------------
+//
+ CNATFWSTUNSrvImpl::~CNATFWSTUNSrvImpl()
+    {
+    __STUNSERVER( "CNATFWSTUNSrvImpl::~CNATFWSTUNSrvImpl" )
+    
+    iIdentificationArray.Close();
+    delete iUsername;
+    iMultiplexer = NULL;
+    
+    iTransactionIds.Close();
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::AddAuthenticationParamsL 
+// ---------------------------------------------------------------------------
+//
+void CNATFWSTUNSrvImpl::AddAuthenticationParamsL(
+    const RPointerArray<CNATFWCredentials>& aIdentifications )
+    {    
+    __STUNSERVER( "CNATFWSTUNSrvImpl::AddAuthenticationParamsL" )
+    
+    TInt identificationCount( aIdentifications.Count() );
+    for ( TInt i = 0; i < identificationCount; i++ )
+        {
+        TInt ind( iIdentificationArray.Find( 
+            aIdentifications[i], CNATFWCredentials::Compare ) );
+        if ( KErrNotFound == ind )
+            {
+            iIdentificationArray.AppendL( aIdentifications[i] );
+            iMultiplexer->RegisterIncomingConnectionObserverL( 
+                aIdentifications[i]->StreamId(), *this );
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::RemoveAuthenticationParamsL
+// ---------------------------------------------------------------------------
+//     
+void CNATFWSTUNSrvImpl::RemoveAuthenticationParamsL( 
+    const RPointerArray<CNATFWCredentials>& aIdentifications )
+    {
+     __STUNSERVER( "CNATFWSTUNSrvImpl::RemoveAuthenticationParamsL" )
+    
+    TInt removeCount( aIdentifications.Count() );
+    while ( removeCount-- )
+        {
+        TInt ind( iIdentificationArray.Find( 
+            aIdentifications[removeCount], CNATFWCredentials::Compare ) );
+        
+        if ( KErrNotFound != ind )
+            {
+            iMultiplexer->UnregisterIncomingConnectionObserverL( 
+                aIdentifications[removeCount]->StreamId(), *this );
+            iIdentificationArray.Remove( ind );
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::SetRoleL
+// ---------------------------------------------------------------------------
+//     
+void CNATFWSTUNSrvImpl::SetRoleL( TNATFWIceRole aRole,
+    TUint64 aTieBreaker ) 
+    {
+    __STUNSERVER( "CNATFWSTUNSrvImpl::SetRoleL" )
+    
+    iRole = aRole;
+    iTieBreaker = aTieBreaker;
+    }
+
+
+// ---------------------------------------------------------------------------
+// From class MNcmIncomingConnectionObserver
+// CNATFWSTUNSrvImpl::IncomingMessageL 
+// ---------------------------------------------------------------------------
+//                                        
+void CNATFWSTUNSrvImpl::IncomingMessageL( TUint aStreamId, 
+    const TDesC8& aMessage, const TInetAddr& aLocalAddr, 
+    const TInetAddr& aFromAddr, const TInetAddr& aPeerRemoteAddress,
+    TBool& aConsumed )
+    {
+    __STUNSERVER_ADDRLOG(
+        "CNATFWSTUNSrvImpl::IncomingMessageL LOCAL ADDR: ", aLocalAddr )
+    __STUNSERVER_ADDRLOG(
+        "CNATFWSTUNSrvImpl::IncomingMessageL FROM ADDR: ", aFromAddr )
+    __STUNSERVER_ADDRLOG( 
+        "CNATFWSTUNSrvImpl::IncomingMessageL PEER ADDR: ", aPeerRemoteAddress )
+    
+    aConsumed = EFalse;
+    
+    // decoding validates that message is well formed STUN message
+    CNATFWUNSAFMessage* msg = DecodeMessageL( aMessage );
+    CleanupStack::PushL( msg );
+    
+    TInetAddr peerAddr( aPeerRemoteAddress );
+    SetPeerRemoteAddress( aFromAddr, peerAddr );
+    __STUNSERVER_ADDRLOG( 
+        "CNATFWSTUNSrvImpl::IncomingMessageL NEW PEER ADDR: ", 
+        peerAddr )
+    
+    iRoleConflict = this->IsRoleConflictPresent( *msg );
+
+    iStreamId = aStreamId;
+    iFromAddress = aFromAddr;
+    iPeerAddr = peerAddr;
+    iLocalAddress = aLocalAddr;
+    
+    // Unpack data indication
+    if ( msg->Type() == CNATFWUNSAFMessage::EDataIndication )
+        {
+        __STUNSERVER( "CNATFWSTUNSrvImpl::IncomingMessageL, DATA INDICATION" )
+        
+        iRequestInsideIndication = ETrue;
+        CNATFWUNSAFMessage* prevMsg = msg;
+        const TDesC8& data = static_cast<CNATFWUNSAFDataAttribute*>(
+            msg->Attribute( CNATFWUNSAFAttribute::EData ) )->Value();
+        
+        CleanupStack::Pop( msg );
+        TRAPD( err, msg = DecodeMessageL( data ) );
+        CleanupStack::PushL( msg );
+        if ( KErrNoMemory == err )
+            {
+            User::Leave( err );
+            }
+        else if ( KErrNone != err ||
+             msg->Type() != CNATFWUNSAFMessage::EBindingRequest &&
+             msg->Type() != CNATFWUNSAFMessage::EBindingIndication )
+            {
+             // Not acceptabe. Return pointer to data.
+            iRequestInsideIndication = EFalse;
+            delete prevMsg;
+            CleanupStack::PopAndDestroy( msg );
+            return;
+            }
+        else
+            {
+            //For avoid PC-Lint Note
+            }
+        delete prevMsg;
+        }
+    
+    // STUN binding request and indication are accepted
+    if ( msg->Type() == CNATFWUNSAFMessage::EBindingRequest )
+        {       
+        if ( this->IsRequestValidL( *msg, aMessage ) )
+            {
+            TBool favored = 
+                msg->HasAttribute( CNATFWUNSAFAttribute::EUseCandidate );
+            
+            TUint priority = static_cast<
+                CNATFWUNSAFPriorityAttribute*>( msg->Attribute( 
+                CNATFWUNSAFAttribute::EPriority ) )->Priority(); 
+            
+            // Do not generate callback for retransmitted requests because
+            // that increases call setup time.
+            if ( !IsRetransmittedRequest( *msg ) )
+                {
+                SaveTransactionIdL( msg->TransactionID() );
+                
+                iObserver.STUNRequestReceivedL( aLocalAddr, aFromAddr,
+                    iPeerAddr, priority, favored );
+                }
+            }
+        
+        aConsumed = ETrue;
+        }
+    
+    if ( msg->Type() == CNATFWUNSAFMessage::EBindingIndication )
+        {
+        __STUNSERVER( "CNATFWSTUNSrvImpl::IncomingMessageL - binding indication" )
+        aConsumed = ETrue;
+        }
+    
+    CleanupStack::PopAndDestroy( msg );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::IsRoleConflictPresent 
+// ---------------------------------------------------------------------------
+//     
+TBool CNATFWSTUNSrvImpl::IsRoleConflictPresent( 
+    const CNATFWUNSAFMessage& aRequest )
+    {
+    __STUNSERVER( "CNATFWSTUNSrvImpl::IsRoleConflictPresent" )
+    
+    if ( EIceRoleControlling == iRole )
+        {
+        if ( aRequest.HasAttribute( CNATFWUNSAFAttribute::EIceControlling ) )
+            {            
+            TUint64 tiebreaker = 
+                static_cast<CNATFWUNSAFIceControllingAttribute*>( 
+                aRequest.Attribute( CNATFWUNSAFAttribute::EIceControlling ) )
+                ->IceControlling();
+            
+            if ( iTieBreaker >= tiebreaker )
+                {
+                return ETrue;
+                }
+            else
+                {
+                iRole = EIceRoleControlled;
+                iObserver.RoleChangeNeeded( EIceRoleControlled );
+                return EFalse;
+                }
+            }
+        }
+    
+    if ( EIceRoleControlled == iRole )
+        {
+        if ( aRequest.HasAttribute( CNATFWUNSAFAttribute::EIceControlled ) )
+            {
+            TUint64 tiebreaker = 
+                static_cast<CNATFWUNSAFIceControlledAttribute*>( 
+                aRequest.Attribute( CNATFWUNSAFAttribute::EIceControlled ) )
+                ->IceControlled();
+            
+            if ( iTieBreaker >= tiebreaker )
+                {
+                iRole = EIceRoleControlling;
+                iObserver.RoleChangeNeeded( EIceRoleControlling );
+                return EFalse;
+                }
+            else
+                {
+                return ETrue;
+                }
+            }
+        }
+    
+    return EFalse; 
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::SetPeerRemoteAddress 
+// ---------------------------------------------------------------------------
+// 
+void CNATFWSTUNSrvImpl::SetPeerRemoteAddress( const TInetAddr& aFromAddr,
+    TInetAddr& aPeerRemoteAddress ) const
+    {
+    if ( aPeerRemoteAddress.IsUnspecified() )
+        {
+        aPeerRemoteAddress = aFromAddr;
+        }
+    }
+    
+    
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::DecodeMessageL
+// ---------------------------------------------------------------------------
+//
+CNATFWUNSAFMessage* CNATFWSTUNSrvImpl::DecodeMessageL( 
+    const TDesC8& aData ) const
+    {
+    __STUNSERVER( "CNATFWSTUNSrvImpl::DecodeMessageL" )
+    
+    CNATFWUNSAFMessageFactory* decoder = CNATFWUNSAFMessageFactory::NewLC();
+    CNATFWUNSAFMessage* msg = decoder->DecodeL( aData );
+    CleanupStack::PopAndDestroy( decoder );    
+    return msg;
+    }
+    
+
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::EncodeMessageL
+// ---------------------------------------------------------------------------
+//
+HBufC8* CNATFWSTUNSrvImpl::EncodeMessageL( 
+    const CNATFWUNSAFMessage& aRequest, const TDesC8& aPassword,
+    const TInt aErrorCode ) const
+    {
+    __STUNSERVER( "CNATFWSTUNSrvImpl::EncodeMessageL" )    
+    
+    CBufBase* message = NULL;       
+         
+    if ( KErrorCode401 == aErrorCode || KErrRoleConflict == aErrorCode )
+        {
+        message = aRequest.EncodeL(); 
+        }
+    else
+        {
+        // ETrue indicates that fingerprint attribute will be added
+        message = aRequest.EncodeL( aPassword, ETrue );
+        } 
+           
+    CleanupStack::PushL( message );
+    TInt length = message->Size();
+    HBufC8* readBuf = HBufC8::NewLC( length );
+    TPtr8 writable( readBuf->Des() );
+    message->Read( 0, writable, length );
+
+    CleanupStack::Pop( readBuf );
+    CleanupStack::PopAndDestroy( message );
+    
+    return readBuf;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::IsRequestValidL
+// ---------------------------------------------------------------------------
+//    
+TBool CNATFWSTUNSrvImpl::IsRequestValidL( const CNATFWUNSAFMessage& aRequest,
+                                          const TDesC8& aByteStream )
+    {
+    __STUNSERVER( "CNATFWSTUNSrvImpl::IsRequestValidL" )
+    
+    TInt errorCode( KErrNone );
+    HBufC8* password = this->GetPassword( aRequest, errorCode );
+    if ( KErrNoMemory == errorCode )
+        {
+        User::Leave( errorCode );
+        }
+    else if ( KErrNone == errorCode )
+        {
+        CleanupStack::PushL( password );
+        }
+    else
+        {
+        // For avoid PC-Lint note
+        }
+    CNATFWUNSAFFingerprintAttribute* fingerPrint = 
+                    static_cast<CNATFWUNSAFFingerprintAttribute*>(
+                    aRequest.Attribute(CNATFWUNSAFAttribute::EFingerprint));
+
+    if ( KErrNone != errorCode ||
+        !aRequest.HasAttribute( CNATFWUNSAFAttribute::EPriority ) ||
+        ( !fingerPrint || !fingerPrint->CheckFingerprintL( aByteStream ) ) )
+        {
+        if ( KErrNone == errorCode )
+            {
+            CleanupStack::PopAndDestroy( password );
+            }
+        return EFalse;
+        }
+    
+    if ( iRoleConflict )
+        {
+        errorCode = KErrRoleConflict;
+        iRoleConflict = EFalse;
+        }
+    __STUNSERVER_STR8( "CNATFWSTUNSrvImpl::IsRequestValidL - PASSWORD:",
+        *password )
+    __STUNSERVER_STR8( "CNATFWSTUNSrvImpl::IsRequestValidL - USERNAME:",
+        *iUsername )
+
+    TBool isValid( EFalse );
+    TRAPD( error, isValid = CheckIntegrityL( aRequest, aByteStream, 
+                                             *password ) );
+    if ( KErrNoMemory == error )
+        {
+        User::Leave( error );
+        }
+    else if ( KErrNone != error || !isValid )
+        {
+        errorCode = KErrorCode401;
+        }
+    else
+        {
+        // For avoid PC-Lint note
+        }
+    
+    this->SendResponseL( aRequest, errorCode, *password );
+    CleanupStack::PopAndDestroy( password );
+    
+    return ( KErrNone == errorCode );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::CheckIntegrityL
+// ---------------------------------------------------------------------------
+//      
+TBool CNATFWSTUNSrvImpl::CheckIntegrityL( const CNATFWUNSAFMessage& aRequest,
+                                          const TDesC8& aByteStream,
+                                          const TDesC8& aPassword )
+    {
+    __STUNSERVER( "CNATFWSTUNSrvImpl::CheckIntegrityL" )
+    
+    TBool isIntegrityOk( EFalse );
+    if ( !aRequest.HasAttribute( CNATFWUNSAFAttribute::EMessageIntegrity ) )
+        {
+        isIntegrityOk = EFalse;
+        }
+    else if ( iRequestInsideIndication )
+        {
+        iRequestInsideIndication = EFalse;
+        
+        HBufC8* msg = this->EncodeMessageL( aRequest, aPassword, KErrNone );
+        CleanupStack::PushL( msg );
+        
+        if ( static_cast<CNATFWUNSAFMessageIntegrityAttribute*>(
+             aRequest.Attribute( CNATFWUNSAFAttribute::EMessageIntegrity ) )
+                ->CheckMessageIntegrityL( *msg, aPassword ) )
+            {
+            isIntegrityOk = ETrue;
+            }
+        
+        CleanupStack::PopAndDestroy( msg );
+        }
+    else if ( static_cast<CNATFWUNSAFMessageIntegrityAttribute*>(
+              aRequest.Attribute( CNATFWUNSAFAttribute::EMessageIntegrity ) )
+                ->CheckMessageIntegrityL( aByteStream, aPassword ) )
+        {
+        isIntegrityOk = ETrue;
+        }
+    else
+        {
+        isIntegrityOk = EFalse;
+        }
+    
+    return isIntegrityOk;
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::GetPasswordL
+// ---------------------------------------------------------------------------
+//    
+HBufC8* CNATFWSTUNSrvImpl::GetPassword( const CNATFWUNSAFMessage& aRequest,
+    TInt& aError )
+    {
+    __STUNSERVER( "CNATFWSTUNSrvImpl::GetPassword" )
+    
+    aError = KErrNone;
+    
+    if ( !aRequest.HasAttribute( CNATFWUNSAFAttribute::EUsername ) )
+        {
+        __STUNSERVER( "CNATFWSTUNSrvImpl::GetPassword, NO USERNAME ATTR" )
+        aError = KErrNotFound;
+        return NULL;
+        }
+    
+    HBufC8* userName = static_cast<CNATFWUNSAFUsernameAttribute*>( 
+        aRequest.Attribute( CNATFWUNSAFAttribute::EUsername ) )->
+        Value().Alloc();
+
+    // quick fix for OOM situation and to prevent crash
+    if ( NULL == userName )
+        {
+        aError = KErrNoMemory;
+        return NULL;
+        }
+
+    delete iUsername;
+    iUsername = NULL;
+    iUsername = userName;
+
+    TInt ind = iUsername->Find( KColon );
+    if ( KErrNotFound == ind )
+        {
+        __STUNSERVER( "CNATFWSTUNSrvImpl::GetPassword - INVALID USERNAME" )
+        aError = KErrNotFound;
+        return NULL;
+        }
+    
+    HBufC8* usernameFragment = iUsername->Left( ind ).Alloc();
+    if ( !usernameFragment )
+        {
+        aError = KErrNoMemory;
+        return NULL;
+        }
+
+    TInt count( iIdentificationArray.Count() );
+    __STUNSERVER_INT1( "CNATFWSTUNSrvImpl::GetPassword - array count: ", count )
+    
+    for ( TInt i = 0; i < count; i++ )
+        {
+        const CNATFWCredentials& ident = *iIdentificationArray[i];
+        
+        if ( CNATFWCredentials::EInbound == ident.Direction() 
+             && 0 <= ident.Username().Compare( *usernameFragment ) )
+            {
+            delete usernameFragment;
+            HBufC8* passwrd = ident.Password().Alloc();
+            if ( !passwrd )
+                {
+                aError = KErrNoMemory;
+                }
+            return passwrd;
+            }
+        }
+    delete usernameFragment;
+    aError = KErrGeneral;
+    return NULL;   
+    }
+    
+ 
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::SendResponseL 
+// ---------------------------------------------------------------------------
+// 
+void CNATFWSTUNSrvImpl::SendResponseL( const CNATFWUNSAFMessage& aRequest,
+                                       TInt aErrorCode,
+                                       const TDesC8& aPassword )
+    {
+    __STUNSERVER( "CNATFWSTUNSrvImpl::SendResponseL" )
+             
+    CNATFWUNSAFMessage* response( NULL );
+    if ( KErrNone != aErrorCode )
+        {
+        TBufC8<KMaxLength> reason;
+    
+        switch( aErrorCode )
+            {
+            case KErrorCode401:
+                reason = KUnauthorized;
+                break;
+            case KErrRoleConflict:
+                reason = KRoleConflict;
+                break;
+            default:
+                User::Leave( KErrArgument );
+                break;
+            }
+
+        // Transaction ID must be same as in the request
+        response = CNATFWUNSAFBindingErrorResponse::NewLC(
+            aRequest.TransactionID() );
+        response->AddAttributeL( 
+            CNATFWUNSAFErrorCodeAttribute::NewLC( aErrorCode, reason ) );
+        CleanupStack::Pop();
+        }
+    else
+        {            
+        response = CNATFWUNSAFBindingResponse::NewLC( 
+            aRequest.TransactionID() );
+      
+        if ( aRequest.HasAttribute( CNATFWUNSAFAttribute::EMagicCookie ) )
+            {
+            response->AddAttributeL( CNATFWUNSAFXorMappedAddressAttribute::NewLC(
+                                     iPeerAddr, aRequest.TransactionID() ) );
+            CleanupStack::Pop();
+            }
+        else
+            {
+            response->AddAttributeL( CNATFWUNSAFMappedAddressAttribute::NewLC( 
+                                     iPeerAddr ) );
+            CleanupStack::Pop();
+            }
+        }
+    HBufC8* msg = this->EncodeMessageL( *response, aPassword, aErrorCode );
+    CleanupStack::PushL( msg );
+    TRAPD( err, iMultiplexer->SendL( iStreamId, *msg, iFromAddress, iPeerAddr ) )
+    if ( KErrNoMemory == err )
+        {
+        User::Leave( err );
+        }
+    CleanupStack::PopAndDestroy( msg );
+    CleanupStack::PopAndDestroy( response );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::IsRetransmittedRequest
+// ---------------------------------------------------------------------------
+//    
+TBool CNATFWSTUNSrvImpl::IsRetransmittedRequest( 
+    const CNATFWUNSAFMessage& aRequest ) const
+    {
+    TNATFWUNSAFTransactionID id = aRequest.TransactionID();
+    
+    if ( KErrNotFound == FindTransactionId( id ) )
+        {
+        __STUNSERVER_STR8( "CNATFWSTUNSrvImpl::IsRetransmittedRequest FALSE",
+            id )
+        return EFalse;
+        }
+    else
+        {
+        __STUNSERVER_STR8( "CNATFWSTUNSrvImpl::IsRetransmittedRequest TRUE",
+            id )
+        return ETrue;
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::SaveTransactionIdL
+// ---------------------------------------------------------------------------
+//
+void CNATFWSTUNSrvImpl::SaveTransactionIdL( 
+    const TNATFWUNSAFTransactionID& aId )
+    {
+    __STUNSERVER_STR8( "CNATFWSTUNSrvImpl::SaveTransactionIdL", aId )
+    
+    if ( KMaxTrackedIdCount == iTransactionIds.Count() )
+        {
+        iTransactionIds.Remove( 0 );
+        }
+    
+    iTransactionIds.AppendL( aId );
+    }
+
+
+// ---------------------------------------------------------------------------
+// CNATFWSTUNSrvImpl::FindTransactionId
+// ---------------------------------------------------------------------------
+//
+TInt CNATFWSTUNSrvImpl::FindTransactionId( 
+        const TNATFWUNSAFTransactionID& aId ) const
+    {
+    TInt foundIdIndex( KErrNotFound );
+    TInt index( iTransactionIds.Count() - 1 );
+    while ( KErrNotFound == foundIdIndex && 0 <= index )
+        {
+        if ( aId == iTransactionIds[index] )
+            {
+            foundIdIndex = index;
+            }
+        
+        index--;
+        }
+    
+    return foundIdIndex;
+    }