--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/natplugins/natptraversalcontroller/src/cnattraversalsession.cpp Tue Feb 02 01:04:58 2010 +0200
@@ -0,0 +1,689 @@
+/*
+* 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 "cnattraversalsession.h"
+#include "cnattraversalconfig.h"
+#include "cnatbinding.h"
+#include "cnatbindingstunrefresher.h"
+#include "cnatbindingcrlfrefresher.h"
+#include "cnatbindingstunandcrlfrefresher.h"
+#include "cudpcrlfsender.h"
+#include "ctcpcrlfsender.h"
+#include "ctlscrlfsender.h"
+#include "sipnatbindingobserver.h"
+#include "nattraversallog.h"
+
+_LIT8(KZeroIPAddress, "0.0.0.0");
+
+// The following addresses are private (RFC 1918):
+// 10.0.0.0 - 10.255.255.255
+const TUint32 KPrivateRange1Low = INET_ADDR(10,0,0,0);
+const TUint32 KPrivateRange1High = INET_ADDR(10,255,255,255);
+
+// 172.16.0.0 - 172.31.255.255
+const TUint32 KPrivateRange2Low = INET_ADDR(172,16,0,0);
+const TUint32 KPrivateRange2High = INET_ADDR(172,31,255,255);
+
+// 192.168.0.0 - 192.168.255.255
+const TUint32 KPrivateRange3Low = INET_ADDR(192,168,0,0);
+const TUint32 KPrivateRange3High = INET_ADDR(192,168,255,255);
+
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::NewL
+// -----------------------------------------------------------------------------
+//
+CNATTraversalSession* CNATTraversalSession::NewL(
+ CDeltaTimer& aDeltaTimer,
+ RSocketServ& aSocketServ,
+ RConnection& aConnection,
+ const TInetAddr& aLocalAddr,
+ const TInetAddr& aNextHopAddr,
+ CNATTraversalConfig* aConfig,
+ MSTUNClientObserver& aObserver,
+ MNATTraversalSocketManager& aSocketManager)
+ {
+ CNATTraversalSession* self =
+ CNATTraversalSession::NewLC(aDeltaTimer,aSocketServ,aConnection,
+ aLocalAddr,aNextHopAddr,aConfig,
+ aObserver,aSocketManager);
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::NewL
+// -----------------------------------------------------------------------------
+//
+CNATTraversalSession* CNATTraversalSession::NewLC(
+ CDeltaTimer& aDeltaTimer,
+ RSocketServ& aSocketServ,
+ RConnection& aConnection,
+ const TInetAddr& aLocalAddr,
+ const TInetAddr& aNextHopAddr,
+ CNATTraversalConfig* aConfig,
+ MSTUNClientObserver& aObserver,
+ MNATTraversalSocketManager& aSocketManager)
+ {
+ CNATTraversalSession* self =
+ new(ELeave)CNATTraversalSession(
+ aLocalAddr,aNextHopAddr,aDeltaTimer,aSocketManager);
+ CleanupStack::PushL(self);
+ self->ConstructL(aSocketServ,aConnection,aConfig,aObserver);
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::CNATTraversalSession
+// -----------------------------------------------------------------------------
+//
+CNATTraversalSession::CNATTraversalSession(
+ const TInetAddr& aLocalAddr,
+ const TInetAddr& aNextHopAddr,
+ CDeltaTimer& aDeltaTimer,
+ MNATTraversalSocketManager& aSocketManager)
+ : iLocalAddr(aLocalAddr),
+ iNextHopAddr(aNextHopAddr),
+ iDeltaTimer(aDeltaTimer),
+ iSocketManager(aSocketManager)
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalSession::ConstructL(
+ RSocketServ& aSocketServ,
+ RConnection& aConnection,
+ CNATTraversalConfig* aConfig,
+ MSTUNClientObserver& aObserver)
+ {
+ __ASSERT_ALWAYS(aConfig, User::Leave(KErrArgument));
+
+ if (aConfig->STUNServer().Compare(KZeroIPAddress) == 0)
+ {
+ // With 0.0.0.0 STUN server address, STUN is not used.
+ // With this configuration CRLF bursts are sent
+ // to keep the possible firewall hole open.
+ __ASSERT_ALWAYS(aConfig->CRLFRefreshEnabledToProxyValue() ==
+ CNATTraversalConfig::EEnabled,
+ User::Leave(KErrArgument));
+ }
+ else
+ {
+ TBool stunServerConfigured = ETrue;
+ TPtrC8 stunServerPtr(aConfig->STUNServer());
+ if (stunServerPtr.Length() == 0)
+ {
+ stunServerPtr.Set(aConfig->Domain());
+ stunServerConfigured = EFalse;
+ }
+
+ iSTUNClient = CSTUNClient::NewL(aConfig->STUNRetransmitTimer(),
+ stunServerPtr,
+ aConfig->STUNServerPort(),
+ KStun,
+ aSocketServ,
+ aConnection,
+ iDeltaTimer,
+ aObserver,
+ ETrue,
+ !stunServerConfigured);
+
+ if (aConfig->Username().Length() && aConfig->Password().Length())
+ {
+ iSTUNClient->SetCredentialsL(aConfig->Username(),
+ aConfig->Password());
+ }
+ }
+
+ // transfer the ownership only after calling all the leaving functions
+ iConfig = aConfig;
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::~CNATTraversalSession
+// -----------------------------------------------------------------------------
+//
+CNATTraversalSession::~CNATTraversalSession()
+ {
+ delete iSTUNClient;
+ delete iConfig;
+ iBindings.ResetAndDestroy();
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::HasSTUNClient
+// -----------------------------------------------------------------------------
+//
+TBool CNATTraversalSession::HasSTUNClient(const CSTUNClient& aClient) const
+ {
+ return (iSTUNClient == &aClient);
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::Domain
+// -----------------------------------------------------------------------------
+//
+const TDesC8& CNATTraversalSession::Domain() const
+ {
+ return iConfig->Domain();
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::IapId
+// -----------------------------------------------------------------------------
+//
+TUint32 CNATTraversalSession::IapId() const
+ {
+ return iConfig->IapId();
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::UpdateNextHop
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalSession::UpdateNextHop(const TInetAddr& aNextHopAddr)
+ {
+ iNextHopAddr = aNextHopAddr;
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::HasBindings
+// -----------------------------------------------------------------------------
+//
+TBool CNATTraversalSession::HasBindings() const
+ {
+ return (iBindings.Count() > 0);
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::HasBinding
+// -----------------------------------------------------------------------------
+//
+TBool CNATTraversalSession::HasBinding(
+ const MSIPNATBindingObserver* aObserver) const
+ {
+ return (FindBindingIndex(aObserver) >= 0);
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::InitCompletedL
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalSession::InitCompletedL()
+ {
+ NATTRAVERSAL_LOG("CNATTraversalSession::InitCompletedL")
+ __ASSERT_ALWAYS(iSTUNClient, User::Leave(KErrCorrupt));
+ iConfig->SetSharedSecretNotSupportedL(!iSTUNClient->SharedSecretObtained());
+ for (TInt i=0; i<iBindings.Count(); i++)
+ {
+ CNATBinding* bindingHolder = iBindings[i];
+ CSTUNBinding* stunBinding =
+ CSTUNBinding::NewL(*iSTUNClient,bindingHolder->STUNSocket());
+ bindingHolder->SetBinding(stunBinding);
+ bindingHolder->SendSTUNRequestL();
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::InitFailed
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalSession::InitFailed(TInt aError)
+ {
+ NATTRAVERSAL_LOG("CNATTraversalSession::InitFailedL")
+ TRAP_IGNORE(iConfig->SetBindingRequestFailedL(ETrue))
+ for (TInt i=iBindings.Count()-1; i>=0; i--)
+ {
+ iBindings[i]->SetBindingFailed(aError);
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::AddressResolvedL
+// -----------------------------------------------------------------------------
+//
+TBool CNATTraversalSession::AddressResolvedL(const CBinding& aBinding)
+ {
+ NATTRAVERSAL_ADDRLOG("CNATTraversalSession::AddressResolvedL",
+ aBinding.PublicAddr())
+ TBool found = EFalse;
+ for (TInt i=iBindings.Count()-1; i>=0 && !found; i--)
+ {
+ CNATBinding* bindingHolder = iBindings[i];
+ if (bindingHolder->Binding() == &aBinding)
+ {
+ found = ETrue;
+ TBool publicAddrChanged =
+ bindingHolder->SetPublicAddr(aBinding.PublicAddr());
+ if (publicAddrChanged)
+ {
+ // Existing public address has changed -> flow failure
+ iBindings.Remove(i);
+ bindingHolder->NATBindingObserver().FlowFailure(KErrGeneral);
+ delete bindingHolder;
+ }
+ else
+ {
+ bindingHolder->ContinueRefreshing();
+ }
+ }
+ }
+ return found;
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::BindingFailed
+// -----------------------------------------------------------------------------
+//
+TBool CNATTraversalSession::BindingFailed(
+ const CBinding& aBinding,
+ TInt aError)
+ {
+ TBool found = EFalse;
+ for (TInt i=iBindings.Count()-1; i>=0 && !found; i--)
+ {
+ CNATBinding* bindingHolder = iBindings[i];
+ if (bindingHolder->Binding() == &aBinding)
+ {
+ found = ETrue;
+ TRAP_IGNORE(iConfig->SetBindingRequestFailedL(ETrue))
+ bindingHolder->SetBindingFailed(aError);
+ }
+ }
+ return found;
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::CreateNATBindingL
+// -----------------------------------------------------------------------------
+//
+CNATBinding& CNATTraversalSession::CreateNATBindingL(
+ TUint32 aRequestId,
+ RSocket& aSocket,
+ MSIPNATBindingObserver& aBindingObserver,
+ MSIPNATTraversalRequestObserver& aRequestObserver,
+ TBool& aAsyncCallInitiated)
+ {
+ aAsyncCallInitiated = EFalse;
+ // Initialize binding's public address with the local address
+ CNATBinding* bindingHolder =
+ CNATBinding::NewLC(aRequestId,aSocket,iLocalAddr,
+ aRequestObserver,aBindingObserver,
+ iSocketManager);
+
+ if (iSTUNClient)
+ {
+ // STUN used, not only CRLF-refreshes.
+ if (iSTUNClient->IsInitialized())
+ {
+ if (!iConfig->BindingRequestFailed())
+ {
+ CSTUNBinding* stunBinding =
+ CSTUNBinding::NewL(
+ *iSTUNClient,bindingHolder->STUNSocket());
+ bindingHolder->SetBinding(stunBinding);
+ bindingHolder->SendSTUNRequestL();
+ aAsyncCallInitiated = ETrue;
+ }
+ }
+ else
+ {
+ // STUN Client is not initialized.
+ aAsyncCallInitiated = (!iConfig->BindingRequestFailed());
+ }
+ }
+
+ iBindings.AppendL(bindingHolder);
+ CleanupStack::Pop(bindingHolder);
+ return *bindingHolder;
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::RefreshNATBindingL
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalSession::RefreshNATBindingL(
+ RSocket& aSocket,
+ const MSIPNATBindingObserver* aBindingObserver,
+ TBool& aMaintainPersistentConnection,
+ TBool& aHandled)
+ {
+ aMaintainPersistentConnection = EFalse;
+ aHandled = EFalse;
+ TInt index = FindBindingIndex(aBindingObserver);
+ if (index >= 0)
+ {
+ CNATBinding* binding = iBindings[index];
+ if (!binding->Refresher() &&
+ (IsBehindNAT(*binding) ||
+ iConfig->CRLFRefreshEnabledToProxy(Protocol(aSocket))))
+ {
+ CreateRefresherL(*binding,aSocket,aMaintainPersistentConnection);
+ }
+ aMaintainPersistentConnection = binding->PersistentConnectionRequired();
+ aHandled = ETrue;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::RefreshNATBindingL
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalSession::RefreshNATBindingL(
+ CSecureSocket& aSecureSocket,
+ const MSIPNATBindingObserver* aBindingObserver,
+ TBool& aMaintainPersistentConnection,
+ TBool& aHandled)
+ {
+ aMaintainPersistentConnection = EFalse;
+ aHandled = EFalse;
+ TInt index = FindBindingIndex(aBindingObserver);
+ if (index >= 0)
+ {
+ CNATBinding* binding = iBindings[index];
+ if (!binding->Refresher() &&
+ (IsBehindNAT(*binding) ||
+ iConfig->CRLFRefreshEnabledToProxy(KProtocolInetTcp)))
+ {
+ CTlsCRLFSender* sender =
+ new(ELeave)CTlsCRLFSender(aSecureSocket,*binding);
+ CleanupStack::PushL(sender);
+ CNATBindingRefresher* refresher =
+ new(ELeave)CNATBindingCRLFRefresher(
+ iDeltaTimer,
+ iConfig->TCPRefreshInterval(),
+ *binding,
+ sender);
+ CleanupStack::Pop(sender);
+ binding->SetRefresher(refresher);
+ }
+ aMaintainPersistentConnection = binding->PersistentConnectionRequired();
+ aHandled = ETrue;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::SocketIdle
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalSession::SocketIdle(
+ TBool aIdle,
+ RSocket& aSocket)
+ {
+ SocketIdleImpl(aIdle,aSocket);
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::SocketIdle
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalSession::SocketIdle(
+ TBool aIdle,
+ CSecureSocket& aSocket)
+ {
+ SocketIdleImpl(aIdle,aSocket);
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::DataReceivedL
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalSession::DataReceivedL(
+ const TDesC8& aData,
+ const RSocket& aSocket,
+ TBool& aHandled)
+ {
+ for (TInt i=0; i<iBindings.Count() && !aHandled; i++)
+ {
+ iBindings[i]->HandleDataL(aData,aSocket,aHandled);
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::RemoveBinding
+// -----------------------------------------------------------------------------
+//
+TBool CNATTraversalSession::RemoveBinding(TUint32 aRequestId)
+ {
+ TBool found = EFalse;
+ for (TInt i=0; i<iBindings.Count() && !found; i++)
+ {
+ CNATBinding* binding = iBindings[i];
+ if (binding->InitialRequestId() == aRequestId)
+ {
+ iBindings.Remove(i);
+ delete binding;
+ found = ETrue;
+ }
+ }
+ return found;
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::RemoveBinding
+// -----------------------------------------------------------------------------
+//
+TBool CNATTraversalSession::RemoveBinding(
+ const MSIPNATBindingObserver& aObserver)
+ {
+ TBool found = EFalse;
+ TInt index = FindBindingIndex(&aObserver);
+ if (index >= 0)
+ {
+ CNATBinding* binding = iBindings[index];
+ iBindings.Remove(index);
+ delete binding;
+ found = ETrue;
+ }
+ return found;
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::DetachConfig
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalSession::DetachConfig()
+ {
+ iConfig = NULL;
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::Protocol
+// -----------------------------------------------------------------------------
+//
+TUint CNATTraversalSession::Protocol(RSocket& aSocket) const
+ {
+ TProtocolDesc proto;
+ aSocket.Info(proto);
+ return proto.iProtocol;
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::RefreshInterval
+// -----------------------------------------------------------------------------
+//
+TInt CNATTraversalSession::RefreshInterval(TUint aProtocol) const
+ {
+ TInt interval = 0;
+ if (aProtocol == KProtocolInetTcp)
+ {
+ interval = iConfig->TCPRefreshInterval();
+ }
+ if (aProtocol == KProtocolInetUdp)
+ {
+ interval = iConfig->UDPRefreshInterval();
+ }
+ return interval;
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::FindBindingIndex
+// -----------------------------------------------------------------------------
+//
+TInt CNATTraversalSession::FindBindingIndex(
+ const MSIPNATBindingObserver* aBindingObserver) const
+ {
+ TInt index = KErrNotFound;
+ for (TInt i=0; i < iBindings.Count() && index == KErrNotFound; i++)
+ {
+ CNATBinding* binding = iBindings[i];
+ if (&(binding->NATBindingObserver()) == aBindingObserver)
+ {
+ index = i;
+ }
+ }
+ return index;
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::CreateRefresherL
+// -----------------------------------------------------------------------------
+//
+void CNATTraversalSession::CreateRefresherL(
+ CNATBinding& aBinding,
+ RSocket& aSocket,
+ TBool& aMaintainPersistentConnection)
+ {
+ aMaintainPersistentConnection = EFalse;
+ CNATBindingRefresher* refresher = NULL;
+ TUint protocol = Protocol(aSocket);
+ TInt refreshInterval = RefreshInterval(protocol);
+ if (protocol == KProtocolInetTcp)
+ {
+ CTcpCRLFSender* sender =
+ new(ELeave)CTcpCRLFSender(aSocket,aBinding);
+ CleanupStack::PushL(sender);
+ refresher = new(ELeave)CNATBindingCRLFRefresher(iDeltaTimer,
+ refreshInterval,
+ aBinding,
+ sender);
+ CleanupStack::Pop(sender);
+ aMaintainPersistentConnection = ETrue;
+ }
+ else if (protocol == KProtocolInetUdp)
+ {
+ if (IsBehindNAT(aBinding) && aBinding.AddressResolved())
+ {
+ // STUN has been succesfully used to detect a NAT
+ if (iSTUNClient &&
+ iNextHopAddr.Match(iSTUNClient->STUNServerAddrL()))
+ {
+ // Next hop has a STUN server -> refresh using STUN
+ refresher =
+ new(ELeave)CNATBindingSTUNRefresher(iDeltaTimer,
+ refreshInterval,
+ aBinding,
+ aBinding);
+ }
+ else
+ {
+ // Refresh using STUN towards STUN server and
+ // using CRLF towards the SIP proxy
+ refresher = CNATBindingSTUNAndCRLFRefresher::NewL(
+ iDeltaTimer,refreshInterval,aBinding,
+ aBinding,aSocket,iNextHopAddr,iSocketManager);
+ }
+ }
+ else
+ {
+ if (iConfig->CRLFRefreshEnabledToProxy(protocol))
+ {
+ CUdpCRLFSender* sender =
+ new(ELeave)CUdpCRLFSender(
+ aSocket,iNextHopAddr,aBinding,iSocketManager);
+ CleanupStack::PushL(sender);
+ refresher =
+ new(ELeave)CNATBindingCRLFRefresher(
+ iDeltaTimer,refreshInterval,aBinding,sender);
+ CleanupStack::Pop(sender);
+ }
+ }
+ }
+ else
+ {
+ User::Leave(KErrNotSupported);
+ }
+ aBinding.SetRefresher(refresher);
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::SocketIdleImpl
+// -----------------------------------------------------------------------------
+//
+template<class T> void CNATTraversalSession::SocketIdleImpl(
+ TBool aIdle,
+ T& aSocket)
+ {
+ for (TInt i=0; i<iBindings.Count(); i++)
+ {
+ CNATBindingRefresher* bindingRefresher = iBindings[i]->Refresher();
+ if (bindingRefresher && bindingRefresher->HasSocket(aSocket))
+ {
+ bindingRefresher->SetRefresh(aIdle);
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::IsBehindNAT
+// -----------------------------------------------------------------------------
+//
+TBool CNATTraversalSession::IsBehindNAT(const CNATBinding& aBinding) const
+ {
+ TBool natDetected = EFalse;
+ if (aBinding.AddressResolved())
+ {
+ if (!aBinding.PublicAddr().Match(iLocalAddr))
+ {
+ natDetected = ETrue;
+ }
+ }
+ else
+ {
+ if (IsPrivateAddress(iLocalAddr))
+ {
+ natDetected = ETrue;
+ }
+ }
+ return natDetected;
+ }
+
+// -----------------------------------------------------------------------------
+// CNATTraversalSession::IsPrivateAddress
+// -----------------------------------------------------------------------------
+//
+TBool CNATTraversalSession::IsPrivateAddress(const TInetAddr& aAddr) const
+ {
+ TBool isPrivate = EFalse;
+ if (aAddr.Family() == KAfInet)
+ {
+ // aAddr is IPv4 address, IPv6 addresses are always public
+ TUint32 addr = aAddr.Address();
+ if ((addr >= KPrivateRange1Low && addr <= KPrivateRange1High) ||
+ (addr >= KPrivateRange2Low && addr <= KPrivateRange2High) ||
+ (addr >= KPrivateRange3Low && addr <= KPrivateRange3High))
+ {
+ isPrivate = ETrue;
+ }
+ }
+ return isPrivate;
+ }
+