vpnengine/ikesocket/src/receiver.cpp
changeset 0 33413c0669b9
child 12 a15e6baef510
--- /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;
+        }
+    }