natplugins/natptraversalcontroller/src/cnattraversalcontroller.cpp
changeset 0 1bce908db942
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/natplugins/natptraversalcontroller/src/cnattraversalcontroller.cpp	Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,598 @@
+/*
+* Copyright (c) 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 "cnattraversalcontroller.h"
+#include "sipnattraversalcontrollerinitparams.h"
+#include "sipnatbindingobserver.h"
+#include "sipnattraversalrequestobserver.h"
+#include "cnattraversalconfig.h"
+#include "cnattraversalsession.h"
+#include "nattraversalsocketuser.h"
+#include "nattraversallog.h"
+#include <siperr.h>
+
+_LIT8(KZeroIPAddress, "0.0.0.0");
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::NewL
+// -----------------------------------------------------------------------------
+//
+CNATTraversalController* CNATTraversalController::NewL(TAny* aInitParams)
+    {
+    __ASSERT_ALWAYS (aInitParams, User::Leave(KErrArgument));
+    TSIPNATTraversalControllerInitParams* params =
+        static_cast<TSIPNATTraversalControllerInitParams*>(aInitParams);
+    CNATTraversalController* self =
+        new(ELeave)CNATTraversalController(params->iSocketServ);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::CNATTraversalController
+// -----------------------------------------------------------------------------
+//
+CNATTraversalController::CNATTraversalController(RSocketServ& aSocketServ)
+ : iSocketServ(aSocketServ),
+   iRequestOrder(TNATTraversalPendingRequest::RequestOrder)
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::ConstructL()
+    {
+    iDeltaTimer = CDeltaTimer::NewL(CActive::EPriorityStandard);
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::~CNATTraversalController
+// -----------------------------------------------------------------------------
+//
+CNATTraversalController::~CNATTraversalController()
+    {
+    iSessions.ResetAndDestroy();
+    for (TInt i=0; i < iPendingRequests.Count(); i++)
+        {
+        if (iDeltaTimer)
+            {
+            iDeltaTimer->Remove(iPendingRequests[i].DeltaTimerEntry());
+            }
+        }
+    iPendingRequests.Close();
+    delete iDeltaTimer;
+    iSocketUserQueue.Close();
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::ResolvePublicAddrL
+// From CSIPNATTraversalController
+// -----------------------------------------------------------------------------
+//
+TUint32 CNATTraversalController::ResolvePublicAddrL(
+    TUint32 aIapId,
+    RConnection& aConnection,
+    const TInetAddr& aLocalAddr,
+    const TDesC8& aDomain,
+    RSocket& aUdpSocket,
+    const TInetAddr& aNextHopAddr,
+    MSIPNATBindingObserver* aBindingObserver,
+    MSIPNATTraversalRequestObserver& aRequestObserver)
+    {
+    __ASSERT_ALWAYS(NULL != aBindingObserver,User::Leave(KErrArgument));
+    TUint32 requestId = NextRequestId();
+    TBool asyncCallInitiated = EFalse;
+
+    if (!BindingExists(aBindingObserver))
+        {
+        CNATTraversalConfig* config = CNATTraversalConfig::NewLC(aIapId,aDomain);
+
+        CreateBindingL(requestId,config,aConnection,aLocalAddr,aUdpSocket,
+                       aNextHopAddr,*aBindingObserver,aRequestObserver,
+                       asyncCallInitiated);
+
+        CleanupStack::Pop(config); // ownership transferred
+        }
+
+    if (!asyncCallInitiated)
+        {
+        // Start a timer with a minimum value to make the call asynchronous
+        TNATTraversalPendingRequest request(requestId,&aRequestObserver,*this);
+        iPendingRequests.InsertInOrderL(request,iRequestOrder);
+        TInt index = iPendingRequests.FindInOrder(request,iRequestOrder);
+        if (0 <= index && iPendingRequests.Count() > index)
+            {
+            iDeltaTimer->Queue(1,iPendingRequests[index].DeltaTimerEntry());
+            }
+        }
+
+    return requestId;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::Cancel
+// From CSIPNATTraversalController
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::Cancel(TUint32 aRequestId)
+    {
+    NATTRAVERSAL_LOG("CNATTraversalController::Cancel")
+    TNATTraversalPendingRequest tmp(aRequestId,0,*this);
+    TInt index = iPendingRequests.FindInOrder(tmp,iRequestOrder);
+    if (0 <= index && iPendingRequests.Count() > index)
+        {
+        iDeltaTimer->Remove(iPendingRequests[index].DeltaTimerEntry());
+        iPendingRequests.Remove(index);
+        }
+    else
+        {
+        TBool found = EFalse;
+        for (TInt i=0; i < iSessions.Count() && !found; i++)
+            {
+            found = iSessions[i]->RemoveBinding(aRequestId);
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::RefreshNATBindingL
+// From CSIPNATTraversalController
+// -----------------------------------------------------------------------------
+//
+TBool CNATTraversalController::RefreshNATBindingL(
+    RSocket& aSocket,
+    const MSIPNATBindingObserver* aBindingObserver)
+    {
+    NATTRAVERSAL_LOG("CNATTraversalController::RefreshNATBindingL - TCP/UDP")
+    TBool maintainPersistentConnection = EFalse;
+    TBool handled = EFalse;
+    for (TInt i=0; i < iSessions.Count() && !handled; i++)
+        {
+        iSessions[i]->RefreshNATBindingL(
+            aSocket,aBindingObserver,
+            maintainPersistentConnection,handled);
+        }
+    return maintainPersistentConnection;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::RefreshNATBindingL
+// From CSIPNATTraversalController
+// -----------------------------------------------------------------------------
+//
+TBool CNATTraversalController::RefreshNATBindingL(
+    CSecureSocket& aSecureSocket,
+    const MSIPNATBindingObserver* aBindingObserver)
+    {
+    NATTRAVERSAL_LOG("CNATTraversalController::RefreshNATBindingL - TLS")
+    TBool maintainPersistentConnection = EFalse;
+    TBool handled = EFalse;
+    for (TInt i=0; i < iSessions.Count() && !handled; i++)
+        {
+        iSessions[i]->RefreshNATBindingL(
+            aSecureSocket,aBindingObserver,
+            maintainPersistentConnection,handled);
+        }
+    return maintainPersistentConnection;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::UpdateNextHop
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::UpdateNextHop(
+    const TInetAddr& aNextHopAddr,
+    const MSIPNATBindingObserver* aBindingObserver)
+    {
+    NATTRAVERSAL_ADDRLOG("CNATTraversalController::UpdateNextHop ->",
+        aNextHopAddr)
+    for (TInt i=0; i < iSessions.Count(); i++)
+        {
+        CNATTraversalSession* session = iSessions[i];
+        if (session->HasBinding(aBindingObserver))
+            {
+            session->UpdateNextHop(aNextHopAddr);
+            return;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::SocketIdle
+// From CSIPNATTraversalController
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::SocketIdle(
+    TBool aIdle,
+    RSocket& aSocket)
+    {
+    NATTRAVERSAL_INTLOG("CNATTraversalController::SocketIdle - TCP/UDP", aIdle)
+    for (TInt i=0; i < iSessions.Count(); i++)
+        {
+        iSessions[i]->SocketIdle(aIdle,aSocket);
+        }
+    if (!aIdle)
+        {
+        TBool firstRemoved = EFalse;
+        for (TInt i=iSocketUserQueue.Count()-1; i >= 0; i--)
+            {
+            const RSocket& socket = iSocketUserQueue[i]->Socket();
+            if (socket.SubSessionHandle() == aSocket.SubSessionHandle())
+                {
+                iSocketUserQueue[i]->CancelSending();
+                iSocketUserQueue.Remove(i);
+                firstRemoved = (i == 0);
+                }
+            }
+        if (firstRemoved)
+            {
+            HandleNextFromSocketUserQueue();
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::SocketIdle
+// From CSIPNATTraversalController
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::SocketIdle(
+    TBool aIdle,
+    CSecureSocket& aSecureSocket)
+    {
+    NATTRAVERSAL_INTLOG("CNATTraversalController::SocketIdle - TLS", aIdle)
+    for (TInt i=0; i < iSessions.Count(); i++)
+        {
+        iSessions[i]->SocketIdle(aIdle,aSecureSocket);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::DataReceived
+// From CSIPNATTraversalController
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::DataReceivedL(
+    const TDesC8& aData,
+    const RSocket& aSocket,
+    TBool& aHandled)
+    {
+    NATTRAVERSAL_LOG("CNATTraversalController::DataReceivedL");
+    aHandled = EFalse;
+    for (TInt i=0; i < iSessions.Count() && !aHandled; i++)
+        {
+        iSessions[i]->DataReceivedL(aData,aSocket,aHandled);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::FreeResources
+// From CSIPNATTraversalController
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::FreeResources(TUint32 aIapId)
+    {
+    NATTRAVERSAL_LOG("CNATTraversalController::FreeResources for IAP")
+    for (TInt i = iSessions.Count()-1; i >= 0; i--)
+        {
+        CNATTraversalSession* session = iSessions[i];
+        if (session->IapId() == aIapId)
+            {
+            iSessions.Remove(i);
+            delete session;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::FreeResources
+// From CSIPNATTraversalController
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::FreeResources(
+    MSIPNATBindingObserver& aBindingObserver)
+    {
+    NATTRAVERSAL_LOG("CNATTraversalController::FreeResources for observer")
+    for (TInt i=iSessions.Count()-1; i>=0; i--)
+        {
+        CNATTraversalSession* session = iSessions[i];
+        session->RemoveBinding(aBindingObserver);
+        if (!session->HasBindings())
+            {
+            iSessions.Remove(i);
+            delete session;
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::RequestCompleted
+// From MNATTraversalPendingRequestContainer
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::RequestCompleted(
+    TUint32 aRequestId)
+    {
+    NATTRAVERSAL_LOG("CNATTraversalController::RequestCompleted")
+    TNATTraversalPendingRequest tmp(aRequestId,0,*this);
+    TInt index = iPendingRequests.FindInOrder(tmp,iRequestOrder);
+    if (0 <= index && iPendingRequests.Count() > index)
+        {
+        TNATTraversalPendingRequest request = iPendingRequests[index]; // copy
+        iDeltaTimer->Remove(iPendingRequests[index].DeltaTimerEntry());
+        iPendingRequests.Remove(index); // remove from array
+        request.CompleteRequest(); // use copy for informing the observer
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::STUNClientInitCompleted
+// From MSTUNClientObserver
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::STUNClientInitCompleted(
+    const CSTUNClient& aClient,
+    TInt aCompletionCode)
+    {
+    TBool found = EFalse;
+    for (TInt i=0; i<iSessions.Count() && !found; i++)
+        {
+        CNATTraversalSession* session = iSessions[i];
+        if (session->HasSTUNClient(aClient))
+            {
+            found = ETrue;
+            if (aCompletionCode != KErrNone)
+                {
+                if (KErrNATFWDnsFailure == aCompletionCode)
+                    {
+                    aCompletionCode = KErrSIPResolvingFailure;
+                    }
+                session->InitFailed(aCompletionCode);
+                }
+            else
+                {
+                TRAPD(err,session->InitCompletedL());
+                if (err)
+                    {
+                    session->InitFailed(err);
+                    }
+                }
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::STUNBindingEventOccurredL
+// From MSTUNClientObserver
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::STUNBindingEventOccurredL(
+    TSTUNBindingEvent aEvent,
+    const CBinding& aBinding)
+    {
+    if (aEvent == MSTUNClientObserver::EPublicAddressResolved)
+        {
+        TBool found = EFalse;
+        for (TInt i=0; i<iSessions.Count() && !found; i++)
+            {
+            CNATTraversalSession* session = iSessions[i];
+            found = session->AddressResolvedL(aBinding);
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::STUNBindingErrorOccurred
+// From MSTUNClientObserver
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::STUNBindingErrorOccurred(
+    const CBinding& aBinding,
+    TInt aError)
+    {
+    TBool found = EFalse;
+    for (TInt i=0; i<iSessions.Count() && !found; i++)
+        {
+        CNATTraversalSession* session = iSessions[i];
+        found = session->BindingFailed(aBinding,aError);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::AddToSendingQueueL
+// From MNATTraversalSocketManager
+// -----------------------------------------------------------------------------
+//
+TBool CNATTraversalController::AddToSendingQueueL(
+    MNATTraversalSocketUser& aUser)
+    {
+    TBool requestPendingForSocket = EFalse;
+    for (TInt i=0; i < iSocketUserQueue.Count(); i++)
+        {
+        const RSocket& socket = iSocketUserQueue[i]->Socket();
+        if (socket.SubSessionHandle() == aUser.Socket().SubSessionHandle())
+            {
+            requestPendingForSocket = ETrue;
+            }
+        }
+    iSocketUserQueue.AppendL(&aUser);
+    return requestPendingForSocket;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::SendingCompleted
+// From MNATTraversalSocketManager
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::SendingCompleted(MNATTraversalSocketUser& aUser)
+    {
+    TInt index = iSocketUserQueue.Find(&aUser);
+    if (index >= 0)
+        {
+        iSocketUserQueue.Remove(index);
+        if (index == 0)
+            {
+            HandleNextFromSocketUserQueue();
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::NextRequestId
+// -----------------------------------------------------------------------------
+//
+TUint32 CNATTraversalController::NextRequestId()
+    {
+    if (iRequestIdCounter == KMaxTUint32)
+        {
+        iRequestIdCounter = 1;
+        }
+    else
+        {
+        iRequestIdCounter++;
+        }
+    return iRequestIdCounter;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::CreateBindingL
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::CreateBindingL(
+    TUint32 aRequestId,
+    CNATTraversalConfig* aConfig,
+    RConnection& aConnection,
+    const TInetAddr& aLocalAddr,
+    RSocket& aUdpSocket,
+    const TInetAddr& aNextHopAddr,
+    MSIPNATBindingObserver& aBindingObserver,
+    MSIPNATTraversalRequestObserver& aRequestObserver,
+    TBool& aAsyncInitiated)
+    {
+    __ASSERT_ALWAYS(aConfig, User::Leave(KErrArgument));
+
+    __ASSERT_ALWAYS(!BindingExists(&aBindingObserver),
+                    User::Leave(KErrAlreadyExists));
+
+    TBool useSTUN = (aConfig->STUNServer().Compare(KZeroIPAddress) != 0);
+    if (!useSTUN)
+        {
+        aAsyncInitiated = EFalse;
+        if ( aConfig->CRLFRefreshEnabledToProxyValue() !=
+        	 CNATTraversalConfig::EEnabled )
+            {
+            // No need to create binding nor a dummy CRLF refresh
+            delete aConfig;
+            return;
+            }
+        }
+
+    TInt index = FindSessionIndex(aConfig->IapId(),aConfig->Domain());
+    if (index >= 0)
+        {
+        // Session exists
+        CNATTraversalSession* session = iSessions[index];
+        session->CreateNATBindingL(aRequestId,aUdpSocket,
+                                   aBindingObserver,aRequestObserver,
+                                   aAsyncInitiated);
+        delete aConfig; // ownership transferred after leaving functions
+        }
+    else
+        {
+        // Create new session and add a binding
+        CNATTraversalSession* session =
+            CNATTraversalSession::NewLC(*iDeltaTimer,iSocketServ,aConnection,
+                                        aLocalAddr,aNextHopAddr,aConfig,
+                                        *this,*this);
+        TCleanupItem cleanupItem(DetachConfigFromSession,session);
+        CleanupStack::PushL(cleanupItem);
+        session->CreateNATBindingL(aRequestId,aUdpSocket,
+                                   aBindingObserver,aRequestObserver,
+                                   aAsyncInitiated);
+        iSessions.AppendL(session);
+        CleanupStack::Pop(); // cleanupItem
+        CleanupStack::Pop(session);
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::FindSessionIndex
+// -----------------------------------------------------------------------------
+//
+TInt CNATTraversalController::FindSessionIndex(
+    TUint32 aIapId,
+    const TDesC8& aDomain) const
+    {
+    for (TInt i=0; i < iSessions.Count(); i++)
+        {
+        CNATTraversalSession* session = iSessions[i];
+        if (session->IapId() == aIapId &&
+            session->Domain().CompareF(aDomain) == 0)
+            {
+            return i;
+            }
+        }
+    return KErrNotFound;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::BindingExists
+// -----------------------------------------------------------------------------
+//
+TBool CNATTraversalController::BindingExists(
+    const MSIPNATBindingObserver* aObserver) const
+    {
+    for (TInt i=0; i < iSessions.Count(); i++)
+        {
+        if (iSessions[i]->HasBinding(aObserver))
+            {
+            return ETrue;
+            }
+        }
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::DetachConfigFromSession
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::DetachConfigFromSession(TAny* aSession)
+    {
+    CNATTraversalSession* session =
+        reinterpret_cast<CNATTraversalSession*>(aSession);
+    if (session)
+        {
+        session->DetachConfig();
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalController::HandleNextFromSocketUserQueue
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalController::HandleNextFromSocketUserQueue()
+    {
+    if (iSocketUserQueue.Count() > 0 && !iSocketUserQueue[0]->IsSending())
+        {
+        iSocketUserQueue[0]->SendingAllowed();
+        }
+    }