--- /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 <es_sock.h>
+#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 <non-ESP marker> is in the beginning of IKE message.
+ // <non-ESP marker> is related to the NAT traversal and it should
+ // exist only if IKE messages received through port 4500.
+ // However, we accept <non-ESP marker> 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;
+ }
+ }