pkiutilities/untrustedcertificatedialog/tsrc/tlsconntest/tlsconnection.cpp
branchRCL_3
changeset 21 09b1ac925e3f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pkiutilities/untrustedcertificatedialog/tsrc/tlsconntest/tlsconnection.cpp	Tue Aug 31 16:04:40 2010 +0300
@@ -0,0 +1,471 @@
+/*
+* Copyright (c) 2010 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:  Secure connections test application
+*
+*/
+
+#include "tlsconnection.h"
+#include <e32debug.h>
+#include <SecureSocket.h>
+#include <ssl_internal.h>       // KSolInetSSL, KSoSSLDomainName
+
+_LIT( KData, "GET index.html" );
+_LIT( KSecureProtocol, "TLS1.0" );
+_LIT( KCommDBIapId, "IAP\\Id" );
+_LIT8( KNewLine, "\n" );
+
+const TInt KRecvBufferLength = 0x4000;
+const TInt KOneSecondInMicroseconds = 1000000;
+
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------
+// CTlsConnection::NewL
+// ---------------------------------------------------------
+//
+CTlsConnection* CTlsConnection::NewL( MTlsConnectionObserver& aObs )
+    {
+    RDebug::Print( _L("CTlsConnection::NewL()") );
+    CTlsConnection* self = new ( ELeave ) CTlsConnection( aObs );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CTlsConnection::~CTlsConnection()
+// -----------------------------------------------------------------------------
+//
+CTlsConnection::~CTlsConnection()
+    {
+    RDebug::Print( _L("CTlsConnection::~CTlsConnection()") );
+    Cancel();
+    iDelayTimer.Close();
+    CloseSession();
+    delete iSendBuffer;
+    delete iSendBufPtr;
+    }
+
+// -----------------------------------------------------------------------------
+// CTlsConnection::ConnectL()
+// -----------------------------------------------------------------------------
+//
+void CTlsConnection::ConnectL( const TDesC& aHostName, TInt aPort, TInt aDelay )
+    {
+    RDebug::Print( _L("CTlsConnection::Connect() host '%S', port %d, delay %d"),
+        &aHostName, aPort, aDelay );
+    CloseConnection();
+
+    // Parameters
+    if( iHostName )
+        {
+        delete iHostName;
+        iHostName = NULL;
+        }
+    iHostName = aHostName.AllocL();
+    iPort = aPort;
+    iDelay = aDelay;
+
+    // Save host name in 8-bit form for server certificate checking
+    if( iHostNameForCertCheck )
+        {
+        delete iHostNameForCertCheck;
+        iHostNameForCertCheck = NULL;
+        }
+    iHostNameForCertCheck = HBufC8::NewL( aHostName.Length() );
+    TPtr8 ptr( iHostNameForCertCheck->Des() );
+    ptr.Copy( aHostName );
+
+    // Convert send data to 8-bit and add newline at the end
+    if( iSendBuffer || iSendBufPtr )
+        {
+        delete iSendBuffer;
+        iSendBuffer = NULL;
+        delete iSendBufPtr;
+        iSendBufPtr = NULL;
+        }
+    iSendBuffer = HBufC8::NewL( KData().Length() + 1 );
+    iSendBufPtr = new( ELeave ) TPtr8( iSendBuffer->Des() );
+    iSendBufPtr->Copy( KData );
+    iSendBufPtr->Append( KNewLine );
+
+    // Connect
+    RDebug::Printf( "CTlsConnection::ConnectL iConnection.Open" );
+    User::LeaveIfError( iConnection.Open( iSockServer ) );
+    RDebug::Printf( "CTlsConnection::ConnectL iConnPref.SetDirection" );
+    iConnPref.SetDirection( ECommDbConnectionDirectionOutgoing );
+    if( iCurrentIap )
+        {
+        // uses the same IAP as before
+        RDebug::Printf( "CTlsConnection::ConnectL SetIapId(%d)", iCurrentIap );
+        iConnPref.SetIapId( iCurrentIap );
+        iConnPref.SetDialogPreference( ECommDbDialogPrefDoNotPrompt );
+        }
+    else
+        {
+        // not defined, prompts the IAP from user
+        RDebug::Printf( "CTlsConnection::ConnectL ECommDbDialogPrefPrompt" );
+        iConnPref.SetDialogPreference( ECommDbDialogPrefPrompt );
+        }
+    StateChange( EConnectingNetwork );
+    RDebug::Printf( "CTlsConnection::ConnectL iConnection.Start" );
+    iConnection.Start( iConnPref, iStatus );
+    SetActive();
+    RDebug::Printf( "CTlsConnection::ConnectL end" );
+    }
+
+// -----------------------------------------------------------------------------
+// CTlsConnection::Disconnect()
+// -----------------------------------------------------------------------------
+//
+void CTlsConnection::Disconnect()
+    {
+    Cancel();
+    CloseConnection();
+    StateChange( EDisconnected );
+    }
+
+// -----------------------------------------------------------------------------
+// CTlsConnection::RunL
+// -----------------------------------------------------------------------------
+//
+void CTlsConnection::RunL()
+    {
+    if( iState == EReading && ( iStatus.Int() == KErrEof || iStatus.Int() == KErrSSLAlertCloseNotify ) )
+        {
+        RDebug::Printf( "CTlsConnection::RunL: EReading, EOF: iStatus = %d", iStatus.Int() );
+        StateChange( EAllDone );
+        }
+    else if( iStatus.Int() == KErrNone )
+        {
+        switch ( iState )
+            {
+            case EConnectingNetwork:
+                RDebug::Printf( "CTlsConnection::RunL: EConnectingNetwork" );
+                if( !iCurrentIap )
+                    {
+                    iConnection.GetIntSetting( KCommDBIapId, iCurrentIap );
+                    }
+                if( iDelay )
+                    {
+                    TTimeIntervalMicroSeconds32 delay( iDelay * KOneSecondInMicroseconds );
+                    iDelayTimer.After( iStatus, delay );
+                    StateChange( EOpeningDelay );
+                    }
+                else
+                    {
+                    iConnection.ProgressNotification( iProgress, iStatus );
+                    StateChange( EResolvingHostName );
+                    }
+                SetActive();
+                break;
+
+            case EOpeningDelay:
+                iConnection.ProgressNotification( iProgress, iStatus );
+                StateChange( EResolvingHostName );
+                SetActive();
+                break;
+
+            case EResolvingHostName:
+                {
+                RDebug::Printf( "CTlsConnection::RunL: EResolvingHostName" );
+                TInt err = iHostResolver.Open( iSockServer, KAfInet, KProtocolInetUdp, iConnection );
+                User::LeaveIfError( err );
+                iHostResolver.GetByName( *iHostName, iNameEntry, iStatus );
+                StateChange( EConnectingServer );
+                SetActive();
+                }
+                break;
+
+            case EConnectingServer:
+                {
+                iRemoteAddr.SetFamily( KAfInet );
+                iRemoteAddr = TInetAddr( iNameEntry().iAddr );
+                iRemoteAddr.SetPort( iPort );
+
+                RDebug::Printf( "CTlsConnection::RunL: EConnectingServer" );
+                TInt err = iSocket.Open( iSockServer, KAfInet, KSockStream, KProtocolInetTcp, iConnection );
+                RDebug::Printf( "CTlsConnection::RunL: iSocket.Open ret %d", err );
+                User::LeaveIfError( err );
+                iSocket.Connect( iRemoteAddr, iStatus );
+                StateChange( EHandshaking );
+                SetActive();
+                }
+                break;
+
+            case EHandshaking:
+                {
+                RDebug::Printf( "CTlsConnection::RunL: EHandshaking" );
+                if( iSecureSocket )
+                    {
+                    delete iSecureSocket;
+                    iSecureSocket = NULL;
+                    }
+                iSecureSocket = CSecureSocket::NewL( iSocket, KSecureProtocol );
+                iSecureSocket->SetDialogMode( EDialogModeAttended );
+                // Server name must be set, otherwise CCTSecurityDialogsAO fails with KErrArgument
+                iSecureSocket->SetOpt( KSoSSLDomainName, KSolInetSSL, *iHostNameForCertCheck );
+                iSecureSocket->StartClientHandshake( iStatus );
+                StateChange( EConnecting );
+                SetActive();
+                }
+                break;
+
+            case EConnecting:
+                {
+                RDebug::Printf( "CTlsConnection::RunL: EConnecting" );
+                // Check if connection is closed
+                const TInt stage( iProgress().iStage );
+                if( stage == KConnectionClosed || stage == KLinkLayerClosed )
+                    {
+                    StateChange( EDisconnected );
+                    }
+                else
+                    {
+                    iConnection.ProgressNotification( iProgress, iStatus );
+                    StateChange( ESending );
+                    SetActive();
+                    }
+                }
+                break;
+
+            case ESending:
+                RDebug::Printf( "CTlsConnection::RunL: ESending" );
+                iSecureSocket->Send( *iSendBufPtr, iStatus, iSendLength );
+                StateChange( EReading );
+                SetActive();
+                break;
+
+            case EReading:
+                iTotalRecvCount += iRecvLength();
+                RDebug::Printf( "CTlsConnection::RunL: EReading, read %d bytes", iTotalRecvCount );
+                iObserver.HandleTransferData( iRecvBuffer->Des(), iTotalRecvCount );
+
+                iRecvBufPtr->Zero();
+                iSecureSocket->RecvOneOrMore( *iRecvBufPtr, iStatus, iRecvLength );
+                SetActive();
+                break;
+
+            default:
+                break;
+            }
+        }
+    else
+        {
+        RDebug::Printf( "CTlsConnection::RunL: ERROR iStatus %d", iStatus.Int() );
+        CloseConnection();
+        StateChange( EDisconnected, iStatus.Int() );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CTlsConnection::DoCancel()
+// ---------------------------------------------------------------------------
+//
+void CTlsConnection::DoCancel()
+    {
+    RDebug::Printf( "CTlsConnection::DoCancel(), iState=%d", iState );
+
+    switch( iState )
+        {
+        case EConnectingNetwork:
+            iConnection.Stop();
+            break;
+
+        case EOpeningDelay:
+            iDelayTimer.Cancel();
+            iConnection.Stop();
+            break;
+
+        case EResolvingHostName:
+            iConnection.CancelProgressNotification();
+            iConnection.Stop();
+            break;
+
+        case EConnectingServer:
+            iHostResolver.Cancel();
+            iConnection.Stop();
+            break;
+
+        case EHandshaking:
+            iSocket.CancelConnect();
+            iConnection.Stop();
+            break;
+
+        case EConnecting:
+            if( iSecureSocket )
+                {
+                iSecureSocket->CancelHandshake();
+                delete iSecureSocket;
+                iSecureSocket = NULL;
+                }
+            iSocket.Close();
+            iConnection.Stop();
+            break;
+
+        case ESending:
+            if( iSecureSocket )
+                {
+                iSecureSocket->CancelSend();
+                delete iSecureSocket;
+                iSecureSocket = NULL;
+                }
+            iSocket.Close();
+            iConnection.Stop();
+            break;
+
+        case EReading:
+            if( iSecureSocket )
+                {
+                iSecureSocket->CancelRecv();
+                delete iSecureSocket;
+                iSecureSocket = NULL;
+                }
+            iSocket.Close();
+            iConnection.Stop();
+            break;
+
+        case EAllDone:
+        case EIdle:
+        case EDisconnected:
+        default:
+            break;
+        }
+
+    StateChange( EDisconnected );
+    }
+
+
+// -----------------------------------------------------------------------------
+// CTlsConnection::RunError()
+// -----------------------------------------------------------------------------
+//
+TInt CTlsConnection::RunError( TInt aError )
+    {
+    RDebug::Printf( "CTlsConnection::RunError, aError: %d", aError );
+    CloseConnection();
+    StateChange( EDisconnected, aError );
+    return KErrNone;
+    }
+
+// -----------------------------------------------------------------------------
+// CTlsConnection::CTlsConnection()
+// -----------------------------------------------------------------------------
+//
+CTlsConnection::CTlsConnection( MTlsConnectionObserver& aObs ) :
+        CActive( CActive::EPriorityStandard ), iObserver( aObs ), iState( ENotInitialized )
+    {
+    CActiveScheduler::Add( this );
+    }
+
+// -----------------------------------------------------------------------------
+// CTlsConnection::ConstructL()
+// -----------------------------------------------------------------------------
+//
+void CTlsConnection::ConstructL()
+    {
+    RDebug::Printf( "CTlsConnection::ConstructL begin" );
+
+    User::LeaveIfError( iDelayTimer.CreateLocal() );
+    RDebug::Printf( "CTlsConnection::ConstructL iSockServer" );
+    User::LeaveIfError( iSockServer.Connect() );
+    RDebug::Printf( "CTlsConnection::ConstructL iConnection" );
+    User::LeaveIfError( iConnection.Open( iSockServer ) );
+    RDebug::Printf( "CTlsConnection::ConstructL buffers" );
+    iRecvBuffer = HBufC8::NewL( KRecvBufferLength );
+    iRecvBufPtr = new( ELeave ) TPtr8( iRecvBuffer->Des() );
+    StateChange( EIdle );
+
+    RDebug::Printf( "CTlsConnection::ConstructL end" );
+    }
+
+// ---------------------------------------------------------------------------
+// CTlsConnection::CloseConnection()
+// ---------------------------------------------------------------------------
+//
+void CTlsConnection::CloseConnection()
+    {
+    RDebug::Printf( "CTlsConnection::CloseConnection begin" );
+    if( iSecureSocket )
+        {
+        delete iSecureSocket;
+        iSecureSocket = NULL;
+        }
+    iSocket.Close();
+    iHostResolver.Close();
+    if( iConnection.SubSessionHandle() )
+        {
+        if( iState >= EConnectingNetwork )
+            {
+            TInt err = iConnection.Stop();
+            if( err != KErrNone )
+                {
+                RDebug::Printf( "iConnection.Stop() failed: %d", err );
+                }
+            }
+        iConnection.Close();
+        }
+    RDebug::Printf( "CTlsConnection::CloseConnection end" );
+    }
+
+// ---------------------------------------------------------------------------
+// CTlsConnection::CloseSession()
+// ---------------------------------------------------------------------------
+//
+void CTlsConnection::CloseSession()
+    {
+    RDebug::Printf( "CTlsConnection::CloseSession" );
+    CloseConnection();
+    iSockServer.Close();
+    delete iHostName;
+    iHostName = NULL;
+    delete iHostNameForCertCheck;
+    iHostNameForCertCheck = NULL;
+    delete iRecvBuffer;
+    iRecvBuffer = NULL;
+    delete iRecvBufPtr;
+    iRecvBufPtr = NULL;
+    StateChange( EDisconnected );
+    }
+
+// -----------------------------------------------------------------------------
+// CTlsConnection::StateChange()
+// -----------------------------------------------------------------------------
+//
+void CTlsConnection::StateChange( TTlsConnectionState aNewState, TInt aError )
+    {
+    RDebug::Printf( "CTlsConnection::StateChange, aNewState=%d, aError=%d", aNewState, aError );
+    if( aNewState != iState && iState != EAllDone )
+        {
+        iState = aNewState;
+        iObserver.HandleNetworkEvent( aNewState, aError );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CTlsConnection::ReadL()
+// ---------------------------------------------------------------------------
+//
+void CTlsConnection::ReadL()
+    {
+    RDebug::Printf( "CTlsConnection::ReadL(), iState=%d", iState );
+
+    TPtr8 recvBuffer = iRecvBuffer->Des();
+    recvBuffer.Zero();
+    iSecureSocket->RecvOneOrMore( recvBuffer, iStatus, iRecvLength );
+    SetActive();
+    }
+