diff -r 000000000000 -r 33413c0669b9 vpnengine/ikesocket/src/receiver.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vpnengine/ikesocket/src/receiver.cpp Thu Dec 17 09:14:51 2009 +0200 @@ -0,0 +1,365 @@ +/* +* 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: Receiver for UDP data +* +*/ + + +#include +#include "receiver.h" +#include "ikemsgheader.h" +#include "ikev2const.h" +#include "ikesocketdefs.h" +#include "ikedebug.h" +#include "ikesocketassert.h" + +using namespace IkeSocket; + +const TInt KMaxIkePacketSize( 65536 ); // Maximum size for UDP packet + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// Two-phased constructor. +// --------------------------------------------------------------------------- +// +CReceiver* CReceiver::NewL( RSocket& aSocket, + MReceiverCallback& aCallback, + MIkeDebug& aDebug ) + { + CReceiver* self = new (ELeave) CReceiver( aSocket, + aCallback, + aDebug ); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +// --------------------------------------------------------------------------- +// Destructor. +// --------------------------------------------------------------------------- +// +CReceiver::~CReceiver() + { + DEBUG_LOG( _L("CReceiver::~CReceiver") ); + Cancel(); + delete iMsg; + } + +// --------------------------------------------------------------------------- +// Constructor. +// --------------------------------------------------------------------------- +// +CReceiver::CReceiver( RSocket& aSocket, + MReceiverCallback& aCallback, + MIkeDebug& aDebug ) + : CActive( EPriorityStandard ), + iState( EIdle ), + iMsgPtr( 0, 0, 0 ), + iSocket( aSocket ), + iCallback( aCallback ), + iDebug( aDebug ) + { + CActiveScheduler::Add( this ); // Added to the Active Scheduler + } + +// --------------------------------------------------------------------------- +// Second phase construction. +// --------------------------------------------------------------------------- +// +void CReceiver::ConstructL() + { + DEBUG_LOG( _L("CReceiver::ConstructL") ); + } + +// --------------------------------------------------------------------------- +// Sets IKE major version. +// --------------------------------------------------------------------------- +// +void CReceiver::SetIkeMajorVersion( const TIkeMajorVersion aIkeMajorVersion ) + { + IKESOCKET_ASSERT( aIkeMajorVersion == EIkeMajorV1 || + aIkeMajorVersion == EIkeMajorV2 ); + + iIkeMajorVersion = aIkeMajorVersion; + } + +// --------------------------------------------------------------------------- +// Starts receive. +// --------------------------------------------------------------------------- +// +void CReceiver::Receive() + { + IKESOCKET_ASSERT( iIkeMajorVersion == EIkeMajorV1 || + iIkeMajorVersion == EIkeMajorV2 ); + + if ( iState == EIdle ) + { + WaitDataAvailable(); + } + } + +// --------------------------------------------------------------------------- +// Cancels receive. +// --------------------------------------------------------------------------- +// +void CReceiver::CancelReceive() + { + Cancel(); + + delete iMsg; + iMsg = NULL; + iMsgPtr.Set( 0, 0, 0 ); + + iState = EIdle; + } + +// --------------------------------------------------------------------------- +// Waits for data to become available for reading. +// --------------------------------------------------------------------------- +// +void CReceiver::WaitDataAvailable() + { + IKESOCKET_ASSERT( iState == EIdle ); + IKESOCKET_ASSERT( !IsActive() ); + + iState = EWaitingData; + delete iMsg; + iMsg = NULL; + + iFlags() = KSockSelectRead | KSockSelectExcept; + + iSocket.Ioctl( KIOctlSelect, + iStatus, + &iFlags, + KSOLSocket ); + SetActive(); + } + +// --------------------------------------------------------------------------- +// Receives data from socket. +// --------------------------------------------------------------------------- +// +void CReceiver::ReceiveDataL() + { + IKESOCKET_ASSERT( !IsActive() ); + + iState = EReceiving; + + TInt bytesPending( 0 ); + TInt err = iSocket.GetOpt( KSOReadBytesPending, + KSOLSocket, + bytesPending ); + + User::LeaveIfError( err ); + + if ( bytesPending > KMaxIkePacketSize ) + { + // KMaxIkePacketSize (65536) is max message size supported. + bytesPending = KMaxIkePacketSize; + } + + iMsg = HBufC8::NewL( bytesPending ); + iMsgPtr.Set( iMsg->Des() ); + + iSocket.RecvFrom( iMsgPtr, + iSrcAddr, + 0, + iStatus ); + SetActive(); + } + +// --------------------------------------------------------------------------- +// Handles receive of data. +// --------------------------------------------------------------------------- +// +void CReceiver::HandleDataReceivedL() + { +#ifdef _DEBUG + TBuf<100> txt_addr; + iSrcAddr.Output( txt_addr ); + TUint32 port = iSrcAddr.Port(); + DEBUG_LOG3( _L("CReceiver::HandleDataReceivedL, local port=%d, src address:port=%S:%d"), + iSocket.LocalPort(), &txt_addr, port ); +#endif + + TInt msgLength = iMsgPtr.Length(); + if ( msgLength <= TInt(ISAKMP_HDR_SIZE) ) + { + // Message size smaller than header size. + User::Leave( KErrArgument ); + } + + // Check if is in the beginning of IKE message. + // is related to the NAT traversal and it should + // exist only if IKE messages received through port 4500. + // However, we accept also in IKE message + // received through normal IKE port (500). + const ThdrISAKMP* ikeHdr = ThdrISAKMP::Ptr( iMsgPtr ); + TUint32 octets = BigEndian::Get32( (TUint8*)(ikeHdr) ); + TBool nonEspMarker = ( octets == NON_ESP_MARKER ); + if ( nonEspMarker ) + { + ikeHdr = ikeHdr->GotoOffset( NON_ESP_MARKER_SIZE ); + msgLength -= NON_ESP_MARKER_SIZE; + if ( msgLength <= TInt(ISAKMP_HDR_SIZE) ) + { + // Message size smaller than header size. + User::Leave( KErrArgument ); + } + } + + // Because the received data can be any UDP data transmitted to + // IKE port(s), some checks are done before packet is processed. Length + // value read from header must be greater than ISAKMP_HDR_SIZE. + TInt ikeMsgLength = ikeHdr->GetLength(); + if ( ikeMsgLength <= TInt(ISAKMP_HDR_SIZE) ) + { + User::Leave( KErrArgument ); + } + + // IKE major version in packet MUST be as client expects (1 or 2). + TUint8 majorVersion = ikeHdr->GetMajorVersion(); + if ( majorVersion != iIkeMajorVersion ) + { + User::Leave( KErrArgument ); + } + + NotifyDataReceived(); + } + +// --------------------------------------------------------------------------- +// Handles error in receiving. +// --------------------------------------------------------------------------- +// +void CReceiver::HandleError( const TInt aStatus ) + { + DEBUG_LOG1( _L("CReceiver::HandleError, aStatus=%d"), aStatus ); + + delete iMsg; + iMsg = NULL; + iMsgPtr.Set( 0, 0, 0 ); + iState = EIdle; + + if ( aStatus == KErrDied || + aStatus == KErrServerTerminated || + aStatus == KErrNoMemory ) + { + // Fatal error. Notify client. + iCallback.ReceiveError( aStatus ); + } + else + { + // Error is not fatal. Restart receiving + Receive(); + } + } + +// --------------------------------------------------------------------------- +// Notifies client that data has been received. +// --------------------------------------------------------------------------- +// +void CReceiver::NotifyDataReceived() + { + TInetAddr srcAddr = iSrcAddr; + TInt localPort = iSocket.LocalPort(); + HBufC8* msg = iMsg; + + iMsg = NULL; + iMsgPtr.Set( 0, 0, 0 ); + iState = EIdle; + + // Continue receiving. + Receive(); + + iCallback.DataReceived( msg, // Ownership transferred + srcAddr, + localPort ); + } + +// --------------------------------------------------------------------------- +// From CActive +// Handles a leave occurring in RunL(). +// --------------------------------------------------------------------------- +// +TInt CReceiver::RunError( TInt aError ) + { + HandleError( aError ); + return KErrNone; + } + +// --------------------------------------------------------------------------- +// From CActive +// Handles request completion event about available data or received data. +// --------------------------------------------------------------------------- +// +void CReceiver::RunL() + { + IKESOCKET_ASSERT( iState == EWaitingData || + iState == EReceiving ); + DEBUG_LOG2( _L("CReceiver::RunL, iState=%d, iStatus=%d"), + iState, iStatus.Int() ); + + if ( iStatus.Int() ) + { + HandleError( iStatus.Int() ); + return; + } + + switch ( iState ) + { + case EWaitingData: + { + ReceiveDataL(); + break; + } + case EReceiving: + { + HandleDataReceivedL(); + break; + } + default: + break; + } + } + +// --------------------------------------------------------------------------- +// From CActive +// Implements cancellation of an active request. +// --------------------------------------------------------------------------- +// +void CReceiver::DoCancel() + { + IKESOCKET_ASSERT( iState == EWaitingData || + iState == EReceiving ); + DEBUG_LOG1( _L("CReceiver::DoCancel, iState=%d"), + iState ); + + switch ( iState ) + { + case EWaitingData: + { + iSocket.CancelIoctl(); + break; + } + case EReceiving: + { + iSocket.CancelRecv(); + break; + } + default: + break; + } + }