--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/ikesocket/src/datatransfer.cpp Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,577 @@
+/*
+* Copyright (c) 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: Data transfer functionality
+*
+*/
+
+
+#include "datatransfer.h"
+#include "ikemsgheader.h"
+#include "ikev2const.h"
+#include "localaddressresolver.h"
+#include "ikedebug.h"
+#include "ikesocketassert.h"
+
+using namespace IkeSocket;
+
+const TInt KReceiveQueueMaxCount( 10 );
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// Two-phased constructor.
+// ---------------------------------------------------------------------------
+//
+CDataTransfer* CDataTransfer::NewL( RSocketServ& aSocketServer,
+ RConnection& aConnection,
+ CLocalAddressResolver& aLocalAddressResolver,
+ MDataTransferCallback& aCallback,
+ MIkeDebug& aDebug )
+ {
+ CDataTransfer* self = new (ELeave) CDataTransfer( aSocketServer,
+ aConnection,
+ aLocalAddressResolver,
+ aCallback,
+ aDebug );
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+// Destructor.
+// ---------------------------------------------------------------------------
+//
+CDataTransfer::~CDataTransfer()
+ {
+ DEBUG_LOG( _L("CDataTransfer::~CDataTransfer") );
+
+ CloseSockets();
+ iReceiveQueue.Close();
+
+ delete iSender;
+ delete iReceiver;
+ delete iReceiverNAT;
+ }
+
+// ---------------------------------------------------------------------------
+// Constructor.
+// ---------------------------------------------------------------------------
+//
+CDataTransfer::CDataTransfer( RSocketServ& aSocketServer,
+ RConnection& aConnection,
+ CLocalAddressResolver& aLocalAddressResolver,
+ MDataTransferCallback& aCallback,
+ MIkeDebug& aDebug )
+ : iSocketServer( aSocketServer ),
+ iConnection( aConnection ),
+ iLocalNokiaNATPort( 0 ),
+ iLocalAddressResolver( aLocalAddressResolver ),
+ iErrorCallback( aCallback ),
+ iDebug( aDebug )
+ {
+ }
+
+// ---------------------------------------------------------------------------
+// Second phase construction.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::ConstructL()
+ {
+ DEBUG_LOG( _L("CDataTransfer::ConstructL") );
+
+ iSender = CSender::NewL( iSocket,
+ iSocketNAT,
+ iSocketNokiaNAT,
+ *this,
+ iDebug );
+ iReceiver = CReceiver::NewL( iSocket,
+ *this,
+ iDebug );
+
+ iReceiverNAT = CReceiver::NewL( iSocketNAT,
+ *this,
+ iDebug );
+ }
+
+// ---------------------------------------------------------------------------
+// Sets IKE major version to receivers.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::SetIkeMajorVersion( const TIkeMajorVersion aIkeMajorVersion )
+ {
+ IKESOCKET_ASSERT( iReceiver );
+ IKESOCKET_ASSERT( iReceiverNAT );
+
+ iReceiver->SetIkeMajorVersion( aIkeMajorVersion );
+ iReceiverNAT->SetIkeMajorVersion( aIkeMajorVersion );
+ }
+
+// ---------------------------------------------------------------------------
+// Sets IP version.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::SetIpVersion( const IkeSocket::TIpVersion aIpVersion )
+ {
+ iIpVersion = aIpVersion;
+ }
+
+// ---------------------------------------------------------------------------
+// Opens sockets and binds sockets for ports 500 and 4500.
+// ---------------------------------------------------------------------------
+//
+TInt CDataTransfer::OpenSockets( const TInetAddr& aLocalIp )
+ {
+ IKESOCKET_ASSERT( !iSocketsOpen );
+
+ // Open sockets
+ TInt err = OpenSocket( iSocket );
+
+ if ( err == KErrNone )
+ {
+ err = OpenSocket( iSocketNAT );
+
+ if ( err == KErrNone )
+ {
+ err = OpenSocket( iSocketNokiaNAT );
+ }
+ }
+
+ // Bind sockets for ports 500 and 4500
+ if ( err == KErrNone )
+ {
+ err = BindSocket( iSocket, aLocalIp, KIkePort500 );
+
+ if ( err == KErrNone )
+ {
+ err = BindSocket( iSocketNAT, aLocalIp, KIkePort4500 );
+ }
+ }
+
+ if ( err == KErrNone )
+ {
+ iSocketsOpen = ETrue;
+ }
+ else
+ {
+ // Close sockets if error
+ iSocket.Close();
+ iSocketNAT.Close();
+ iSocketNokiaNAT.Close();
+ iSocketsOpen = EFalse;
+ }
+
+ DEBUG_LOG1( _L("CDataTransfer::OpenSockets, err=%d"), err );
+ return err;
+ }
+
+// ---------------------------------------------------------------------------
+// Closes sockets.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::CloseSockets()
+ {
+ DEBUG_LOG1( _L("CDataTransfer::CloseSockets, sockets open=%d"),
+ iSocketsOpen );
+
+ if ( iSocketsOpen )
+ {
+ // Cancel send and receive.
+ DoCancelSend( KErrDisconnected );
+ DoCancelReceive( KErrDisconnected );
+
+ // Stop receiving.
+ StopReceive();
+
+ // Close sockets.
+ iSocket.Close();
+ iSocketNAT.Close();
+ iSocketNokiaNAT.Close();
+
+ iSocketsOpen = EFalse;
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Sends UDP data.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::SendUdpData( const TInt aLocalPort,
+ const TInetAddr& aDestAddr,
+ const TDesC8& aUdpData,
+ const TUint aDscp,
+ TRequestStatus& aStatus )
+ {
+ TInt err( KErrNone );
+
+ IKESOCKET_ASSERT( iClientStatusSend == NULL );
+ IKESOCKET_ASSERT( iSender );
+
+ iClientStatusSend = &aStatus;
+ *iClientStatusSend = KRequestPending;
+
+ if ( !iSocketsOpen )
+ {
+ err = KErrDisconnected;
+ }
+
+ if ( err == KErrNone )
+ {
+ if ( ( aLocalPort != KIkePort500 ) &&
+ ( aLocalPort != KIkePort4500 ) )
+ {
+ // Nokia NAT keepalive packet.
+ if ( aLocalPort == aDestAddr.Port() )
+ {
+ if ( iLocalNokiaNATPort == 0 )
+ {
+ // Set Nokia NAT Port if not set.
+ err = iSocketNokiaNAT.SetLocalPort( aLocalPort );
+
+ if ( err == KErrNone )
+ {
+ iLocalNokiaNATPort = aLocalPort;
+ }
+ }
+ else if ( iLocalNokiaNATPort != aLocalPort )
+ {
+ // Nokia NAT port cannot be changed
+ // during connection.
+ err = KErrArgument;
+ }
+ else
+ {
+ err = KErrNone;
+ }
+ }
+ else
+ {
+ // Local port does not match destination port.
+ err = KErrArgument;
+ }
+ }
+ }
+
+ if ( err == KErrNone )
+ {
+ err = iSender->SendUdpData( aLocalPort,
+ aDestAddr,
+ aUdpData,
+ aDscp );
+ }
+
+ if ( err )
+ {
+ CompleteSendToClient( err );
+ }
+ }
+
+
+// ---------------------------------------------------------------------------
+// Cancels sending.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::CancelSend()
+ {
+ DoCancelSend();
+ }
+
+// ---------------------------------------------------------------------------
+// Receives UDP data.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::ReceiveUdpData( HBufC8*& aUdpData,
+ TInetAddr& aSrcAddr,
+ TInt& aLocalPort,
+ TRequestStatus& aStatus )
+ {
+ IKESOCKET_ASSERT( iClientStatusReceive == NULL );
+ IKESOCKET_ASSERT( iClientMsgReceive == NULL );
+ IKESOCKET_ASSERT( iClientSrcAddrReceive == NULL );
+ IKESOCKET_ASSERT( iClientLocalPort == NULL );
+
+ // Store client data.
+ iClientStatusReceive = &aStatus;
+ *iClientStatusReceive = KRequestPending;
+ iClientMsgReceive = &aUdpData;
+ iClientSrcAddrReceive = &aSrcAddr;
+ iClientLocalPort = &aLocalPort;
+
+ if ( !iSocketsOpen )
+ {
+ CompleteReceiveToClient( KErrDisconnected );
+ return;
+ }
+
+ iReceivingStopped = EFalse;
+
+ TInt count = iReceiveQueue.Count();
+ if ( count < KReceiveQueueMaxCount )
+ {
+ ReceiveData();
+ }
+
+ if ( count )
+ {
+ // Data is already available.
+ CompleteReceiveToClient( KErrNone );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Cancels receive request.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::CancelReceive()
+ {
+ if ( iClientStatusReceive )
+ {
+ CompleteReceiveToClient( KErrCancel );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Clears available data.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::ClearReceivedData()
+ {
+ DEBUG_LOG( _L("CDataTransfer::ClearReceivedData") );
+
+ CleanupReceiveQueue();
+ ReceiveData();
+ }
+
+// ---------------------------------------------------------------------------
+// Stops receiving. Available data is cleared.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::StopReceive()
+ {
+ DEBUG_LOG( _L("CDataTransfer::StopReceive") );
+
+ CleanupReceiveQueue();
+ DoCancelReceive( KErrCancel );
+ iReceivingStopped = ETrue;
+ }
+
+// ---------------------------------------------------------------------------
+// Gets local IP address.
+// ---------------------------------------------------------------------------
+//
+TInt CDataTransfer::GetLocalAddress( TInetAddr& aLocalIp )
+ {
+ IKESOCKET_ASSERT( iIpVersion == EIPv4 || iIpVersion == EIPv6 );
+ return iLocalAddressResolver.GetLocalAddress( iIpVersion, aLocalIp );
+ }
+
+// ---------------------------------------------------------------------------
+// Notification about completed send from sender.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::SendCompleted( const TInt aStatus )
+ {
+ CompleteSendToClient( aStatus );
+ }
+
+// ---------------------------------------------------------------------------
+// Notification that data has been received.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::DataReceived( HBufC8* aUdpData,
+ const TInetAddr& aSrcAddr,
+ const TInt aLocalPort )
+ {
+ // Store message to receive queue.
+ TReceiveQueueItem item( aUdpData, // Ownership transferred.
+ aSrcAddr,
+ aLocalPort );
+ TInt err = iReceiveQueue.Append( item );
+
+ if ( iReceiveQueue.Count() >= KReceiveQueueMaxCount )
+ {
+ // Queue is full. Cancel receiving.
+ iReceiver->CancelReceive();
+ iReceiverNAT->CancelReceive();
+ }
+
+ if ( iClientStatusReceive )
+ {
+ CompleteReceiveToClient( KErrNone );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Notification about receive error.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::ReceiveError( const TInt aStatus )
+ {
+ if ( iClientStatusReceive )
+ {
+ CompleteReceiveToClient( aStatus );
+ }
+
+ StopReceive();
+
+ iErrorCallback.DataTransferError( aStatus,
+ MDataTransferCallback::EReceiveError );
+ }
+
+// ---------------------------------------------------------------------------
+// Opens socket.
+// ---------------------------------------------------------------------------
+//
+TInt CDataTransfer::OpenSocket( RSocket& aSocket )
+ {
+ TInt err = aSocket.Open( iSocketServer,
+ KAfInet,
+ KSockDatagram,
+ KProtocolInetUdp,
+ iConnection );
+ if ( err == KErrNone )
+ {
+ // Enable multiple binds to same port
+ err = aSocket.SetOpt( KSoReuseAddr, KSolInetIp, 1 );
+ }
+
+ return err;
+ }
+
+// ---------------------------------------------------------------------------
+// Binds socket.
+// ---------------------------------------------------------------------------
+//
+TInt CDataTransfer::BindSocket( RSocket& aSocket,
+ const TInetAddr& aLocalIp,
+ const TInt aLocalPort )
+ {
+ TInt err( KErrNone );
+ TInetAddr localAddr( aLocalIp );
+
+ localAddr.SetPort( aLocalPort );
+ err = aSocket.Bind( localAddr );
+
+#ifdef _DEBUG
+ TBuf<100> txt_addr;
+ aLocalIp.Output( txt_addr );
+ DEBUG_LOG3( _L("Bind socket, address:port=%S:%d, err=%d"),
+ &txt_addr, aLocalPort, err );
+#endif
+
+ return err;
+ }
+
+// ---------------------------------------------------------------------------
+// Cancels sending.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::DoCancelSend( const TInt aCompletionStatus )
+ {
+ iSender->Cancel();
+
+ if ( iClientStatusSend )
+ {
+ CompleteSendToClient( aCompletionStatus );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Cancels receiving.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::DoCancelReceive( const TInt aCompletionStatus )
+ {
+ iReceiver->CancelReceive();
+ iReceiverNAT->CancelReceive();
+
+ if ( iClientStatusReceive )
+ {
+ CompleteReceiveToClient( aCompletionStatus );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Completes send to client.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::CompleteSendToClient( const TInt aStatus )
+ {
+ IKESOCKET_ASSERT( iClientStatusSend );
+
+ User::RequestComplete( iClientStatusSend, aStatus );
+ iClientStatusSend = NULL;
+ }
+
+// ---------------------------------------------------------------------------
+// Completes receive to client.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::CompleteReceiveToClient( const TInt aStatus )
+ {
+ IKESOCKET_ASSERT( iClientStatusReceive );
+ IKESOCKET_ASSERT( iClientMsgReceive );
+ IKESOCKET_ASSERT( iClientSrcAddrReceive );
+ IKESOCKET_ASSERT( iClientLocalPort );
+
+ TInt count = iReceiveQueue.Count();
+
+ if ( ( aStatus == KErrNone ) && count )
+ {
+ // Get oldest item from receive queue.
+ TReceiveQueueItem item = iReceiveQueue[0];
+ iReceiveQueue.Remove( 0 );
+ *iClientMsgReceive = item.UdpData(); // Transfer ownership.
+ *iClientSrcAddrReceive = item.SrcAddr();
+ *iClientLocalPort = item.LocalPort();
+
+ // Need to receive more data if queue was full.
+ ReceiveData();
+ }
+
+ // Complete receive.
+ User::RequestComplete( iClientStatusReceive, aStatus );
+ iClientStatusReceive = NULL;
+ iClientMsgReceive = NULL;
+ iClientSrcAddrReceive = NULL;
+ iClientLocalPort = NULL;
+ }
+
+// ---------------------------------------------------------------------------
+// Receives more data if receiving not requested to be stopped.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::ReceiveData()
+ {
+ if ( !iReceivingStopped )
+ {
+ iReceiver->Receive();
+ iReceiverNAT->Receive();
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// Cleans up data from receive queue.
+// ---------------------------------------------------------------------------
+//
+void CDataTransfer::CleanupReceiveQueue()
+ {
+ while ( iReceiveQueue.Count() )
+ {
+ delete iReceiveQueue[0].UdpData();
+ iReceiveQueue.Remove( 0 );
+ }
+ }
+