diff -r 000000000000 -r 33413c0669b9 vpnengine/ikesocket/src/datatransfer.cpp --- /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 ); + } + } +