Symbian
Symbian OS Library

SYMBIAN OS V9.3

[Index] [Spacer] [Previous] [Next]



SecureSockets: secure sockets example code

Found in: Examples\Networking\SecureSockets\

These are the main files contained in the examples. Some extra files may be needed to run the examples, and these will be found in the appropriate examples directory.

Note: This example is designed to work with TechView and there is no guarantee that it will work with other interfaces.

//
// SecEngine.cpp
//
// Copyright (c) 2001 Symbian Ltd.  All rights reserved.

#include "SecEngine.h"

// Send buffer size
const TInt KSendBufferSize = 256;
// Receive buffer size
const TInt KReceiveBufferSize = 256;

// HTTP messages
_LIT8(KSimpleGet, "GET ");
_LIT8(KNewLine, "\n"); 

// Progress messages
_LIT(KConnnectedMessage, "\nConnecting to %S:%d%S\n");
_LIT(KSecureConnnectingMessage, "\nMaking secure connection");
_LIT(KGettingPageMessage, "\nRequesting web page");
_LIT(KReceivingMessage,"\nReceiving server response");
_LIT(KCipherSuiteInUseMessage,"\nCipher suite in use: %S");
_LIT(KProtocolMessage, "\nProtocol used in connection: %S");
_LIT(KReceivedMessage,"\nReceived server response");
_LIT(KCompleteMessage,"\nTransaction complete: bytes recieved %d");
_LIT(KFileErrorMessage,"\nError in writing data to file");
_LIT(KCancelledMessage,"\nConnection closed");

// State reporting messages
_LIT( KStateErrESocketConnected, "\nError in state ESocketConnected: %d\n" );
_LIT( KStateErrESettingCiphers, "\nError in state ESettingCiphers: %d\n" );
_LIT( KStateErrSecureConnected, "\nError in state ESecureConnected: %d\n" );
_LIT( KStateErrGetRequestSent, "\nError in state EGetRequestSent: %d\n" );
_LIT( KStateErrEDataReceived, "\nError in state EDataReceived: %d\n" );

// Panic code
_LIT( KSecEnginePanic, "SEC-ENGINE");

//
// CSecEngine
//

CSecEngine* CSecEngine::NewL()
    {
    CSecEngine* self = new(ELeave) CSecEngine;
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop();        
    return self;
    }

// Constructor should also call the parent constructor to set the priority
// of the active object.
CSecEngine::CSecEngine() 
: CActive(0), iSndBuffer(0,0), iRcvBuffer(0,0)
    {
    }

CSecEngine::~CSecEngine()
    {
    // Cancel any outstanding request- this cleans up
    // resources created during a connection
    //Cancel(); 
    ConnectionClosed();
    // Clean up engine's permanent resources
    delete (void*)iSndBuffer.Ptr();
    delete (void*)iRcvBuffer.Ptr();
    iTimer.Close();
    iSocketServ.Close();
    }

void CSecEngine::ConstructL()
    {
    iSndBuffer.Set((TUint8*)User::AllocL(KSendBufferSize),0,KSendBufferSize);
    iRcvBuffer.Set((TUint8*)User::AllocL(KReceiveBufferSize),0,KReceiveBufferSize);
    // Connect the socket server
    User::LeaveIfError( iSocketServ.Connect());    
    // Create a local timer
    User::LeaveIfError( iTimer.CreateLocal());
    // Set initial state
    iRunState = ESocketConnected;
    iInUse = EFalse;

    CActiveScheduler::Add( this );
    }

void CSecEngine::ConnectL(const TConnectSettings& aConnectSettings)
    {
    iConnectSettings = &aConnectSettings;

    // Set initial values for flags & buffers
    iSuccess = ETrue;
    iInUse = ETrue;
    iRunState = ESocketConnected;
    iSndBuffer.SetLength( 0 );
    iRcvBuffer.SetLength( 0 );
    iTotalBytesRead = 0;

    // Interpret server address
    if (iInetAddr.Input(iConnectSettings->iAddress) != KErrNone)
        // Success if already in dotted-decimal format
        {
        // Connect to a host resolver (for DNS resolution) - happens sychronously
        User::LeaveIfError( iHostResolver.Open( iSocketServ, KAfInet, KProtocolInetTcp ));
        // Try to resolve symbolic name
        TNameEntry nameEntry;
        User::LeaveIfError (iHostResolver.GetByName( iConnectSettings->iAddress, nameEntry ));
        TSockAddr sockAddr = nameEntry().iAddr;
        iInetAddr = iInetAddr.Cast( sockAddr );
        iHostResolver.Close();
        }
    // Store other connection parameters
    iInetAddr.SetPort( iConnectSettings->iPortNum );
                            
    // Open a TCP socket
    User::LeaveIfError( iSocket.Open( iSocketServ, KAfInet, KSockStream, KProtocolInetTcp ) );   

    // Connect to the server, asynchronously
    iSocket.Connect( iInetAddr, iStatus );   
    SetActive();

    // Print status
    iConsole->Printf(KConnnectedMessage, 
        &iConnectSettings->iAddress, 
        iConnectSettings->iPortNum, 
        &iConnectSettings->iPage ); 
    }

void CSecEngine::SetConsole( CConsoleBase& aConsole )
    {
    iConsole = &aConsole;
    }

void CSecEngine::SetOutputFile( RFile& aOutputFile )
    {
    iOutputFile = &aOutputFile;
    }

TBool CSecEngine::InUse()
    {
    return iInUse;
    }

void CSecEngine::RunL()
    {
    switch ( iRunState )
        {
    case ESocketConnected:
        MakeSecureConnectionL();
        break;

    case ESecureConnected:
        MakePageRequestL();
        break;

    case EGetRequestSent:
        GetServerResponseL();
        break;

    case EDataReceived:
        ReadServerResponseL();
        break;

    case EConnectionClosed:
        ConnectionClosed();
        break;

    default:
        break;
        } // end switch
    }

TInt CSecEngine::RunError( TInt aError )
    {
    // Panic prevents looping
    __ASSERT_ALWAYS(iRunState != EConnectionClosed, 
        User::Panic(KSecEnginePanic,0));

    // do a switch on the state to get the right err message
    switch (iRunState)
        {
        case ESocketConnected:
            iConsole->Printf(KStateErrESocketConnected, aError );
            break;
        case ESettingCiphers:
            iConsole->Printf(KStateErrESettingCiphers, aError );
            break;
        case ESecureConnected:
            iConsole->Printf(KStateErrSecureConnected, aError);
            break;
        case EGetRequestSent:
            iConsole->Printf(KStateErrGetRequestSent, aError);
            break;
        case EDataReceived:
            iConsole->Printf(KStateErrEDataReceived, aError);
            break;
        default:
            break;
        }

    iRunState = EConnectionClosed;
    iSuccess = EFalse;
    iTimer.After( iStatus, 1000000 );
    SetActive();

    return KErrNone;
    }

void CSecEngine::DoCancel()
    {
    iConsole->Printf(KCancelledMessage);
    ConnectionClosed();
    }

void CSecEngine::MakeSecureConnectionL()
    {
    User::LeaveIfError(iStatus.Int()); // errors caught by RunError()

    // Construct the TLS socket, to use the TLS1.0 protocol.
    // Specifying SSL3.0 would also use the same implementation
    iConsole->Printf(KSecureConnnectingMessage);
    _LIT(KTLS1,"TLS1.0");
    iTlsSocket = CSecureSocket::NewL( iSocket, KTLS1 );

    // Set any options before the handshake starts

    // Clears any previous options
    iTlsSocket->FlushSessionCache();
    
/*  Note: You could here set the available ciphers with code such as the following:
    TBuf8<2> buf;
    buf.SetLength(2);
    buf[0]=0; buf[1]=10;
    iTlsSocket->SetAvailableCipherSuites( buf ); */
    
    // start the handshake 
    iTlsSocket->StartClientHandshake( iStatus );

    iRunState = ESecureConnected;
    SetActive();
    }

void CSecEngine::MakePageRequestL()
    {
    // The secure connection has now been made.
    // Send a get request for the page.
    User::LeaveIfError(iStatus.Int());
    iConsole->Printf(KGettingPageMessage);
    
    // Create a GET request
    iSndBuffer+=KSimpleGet;
    iSndBuffer+=iConnectSettings->iPage;
    iSndBuffer+=KNewLine;

    // Send the request
    iRunState = EGetRequestSent;
    iTlsSocket->Send( iSndBuffer, iStatus, iBytesSent );
    SetActive();
    }

void CSecEngine::GetServerResponseL()      
    {
    // The get request has been sent, can now try and receive the data
    User::LeaveIfError(iStatus.Int());
    iConsole->Printf(KReceivingMessage);
    
    // Print the cipher suite that has been negotiated.
    TBuf8<2> buf; 
    User::LeaveIfError(iTlsSocket->CurrentCipherSuite( buf ));
    PrintCipherNameL(buf);

    // Print the protocol version string
    TBuf<32> protocol;
    User::LeaveIfError(iTlsSocket->Protocol( protocol ));
    iConsole->Printf(KProtocolMessage, &protocol );
    
    // Print info about the server's certificate
    const CX509Certificate *servCert = iTlsSocket->ServerCert();
    if ( servCert ) PrintCertInfo( *servCert );
    
    // Read asynchonously-returns when buffer full
    iRunState = EDataReceived;
    iTlsSocket->Recv( iRcvBuffer, iStatus );
    SetActive();
    }

void CSecEngine::ReadServerResponseL()
    {
    // Any error other than KErrEof means the test is a failure
    if (iStatus!=KErrEof) User::LeaveIfError(iStatus.Int());
    iConsole->Printf(KReceivedMessage);

    // Put the received data in the output file & reset the receive buffer
    iTotalBytesRead += iRcvBuffer.Length();
    TInt ret = iOutputFile->Write(iRcvBuffer);
    if (ret != KErrNone) iConsole->Printf(KFileErrorMessage);
    
    // Case 1: error is KErrEof (message complete) or no data received, so stop
    if ( ( iStatus==KErrEof ) || ( iRcvBuffer.Length() == 0 ) )
        {
        iConsole->Printf(KCompleteMessage, iTotalBytesRead);
        // Close the socket neatly
        iRunState = EConnectionClosed;
        iTimer.After( iStatus, 1000000 );
        SetActive();
        return; 
        }

    // Case 2: there's more data to get from the server
    iRcvBuffer.SetLength( 0 );
    iRunState = EDataReceived;
    iTlsSocket->Recv( iRcvBuffer, iStatus );
    SetActive(); 
    }

void CSecEngine::ConnectionClosed()
    {
    if (!iInUse) return;
    // Clean up
    iHostResolver.Close();
    iSocket.CancelAll();
    iTlsSocket->CancelAll();
    iTlsSocket->Close();
    delete iTlsSocket;
    iTlsSocket =0;
    iSocket.Close();

    // Close the output file
    iOutputFile->Close();

    // Wait here for an unload of the ssl.dll to make sure that a session is not
    // reconnected next time. 
    User::After( 1000000 );
    iInUse = EFalse;
    }

void CSecEngine::PrintCipherNameL(const TDes8& aBuf)
    {
    TLex8 lex(aBuf);
    TUint cipherCode=aBuf[1];
    if ((cipherCode<1) || (cipherCode > 0x1B))
        User::Leave(KErrArgument);
    const TText* KCipherNameArray[0x1B] = 
        {
        _S("TLS_RSA_WITH_NULL_MD5"),
        _S("TLS_RSA_WITH_NULL_SHA"),
        _S("TLS_RSA_EXPORT_WITH_RC4_40_MD5"),
        _S("TLS_RSA_WITH_RC4_128_MD5"),
        _S("TLS_RSA_WITH_RC4_128_SHA"),
        _S("TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5"),
        _S("TLS_RSA_WITH_IDEA_CBC_SHA"),
        _S("TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"),
        _S("TLS_RSA_WITH_DES_CBC_SHA"),
        _S("TLS_RSA_WITH_3DES_EDE_CBC_SHA"),
        _S("TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"),
        _S("TLS_DH_DSS_WITH_DES_CBC_SHA"),
        _S("TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"),
        _S("TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"),
        _S("TLS_DH_RSA_WITH_DES_CBC_SHA"),
        _S("TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"),
        _S("TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"),
        _S("TLS_DHE_DSS_WITH_DES_CBC_SHA"),
        _S("TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"),
        _S("TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"),
        _S("TLS_DHE_RSA_WITH_DES_CBC_SHA"),
        _S("TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"),
        _S("TLS_DH_anon_EXPORT_WITH_RC4_40_MD5"),
        _S("TLS_DH_anon_WITH_RC4_128_MD5"),
        _S("TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA"),
        _S("TLS_DH_anon_WITH_DES_CBC_SHA"),
        _S("TLS_DH_anon_WITH_3DES_EDE_CBC_SHA")
        };

    TPtrC name(KCipherNameArray[cipherCode-1]);
    iConsole->Printf(KCipherSuiteInUseMessage, &name );
    }

void CSecEngine::PrintCertInfo(const CX509Certificate& aSource)
    {
    _LIT(KCertInfoMessage1, "\nCertificate received: \n\tIssuer %S \n\tSubject %S");
    _LIT(KCertInfoMessage2, "\n\tValid from %S to %S");
    _LIT(KDateString,"%F%/0%M%/1%Y%/2%D%/3");

    TRAP_IGNORE(
        // Print issuer and subject
        HBufC* issuer = aSource.IssuerL();
        HBufC* subject = aSource.SubjectL();
        iConsole->Printf(KCertInfoMessage1, issuer, subject);
        delete issuer;
        delete subject;
        
        // Print validity period
        TBuf<20> startTime;
        TBuf<20> finishTime;
        aSource.ValidityPeriod().Start().FormatL(startTime,KDateString);
        aSource.ValidityPeriod().Finish().FormatL(finishTime,KDateString);
        iConsole->Printf(KCertInfoMessage2, &startTime, &finishTime);
        );
    }

//
// Copyright (c) 2000-2005 Symbian Software Ltd.  All rights reserved.
//
//
// SecureSockets.CPP
// Definitions of CConsoleControl, CSecAppUi, 
// CSecDocument, CSecApplication

 
#include <eikmenup.h>
#include <eikmfne.h>
#include <eikconso.h>

#include "SecureSockets.h"
#include "SecureSockets.hrh"
    
#include <eikstart.h>




CConsoleControl* CConsoleControl::NewL(const TRect& aClientRect)
    {
    CConsoleControl* self=new (ELeave) CConsoleControl();
    CleanupStack::PushL(self);
    self->ConstructL(aClientRect);
    CleanupStack::Pop();
    return self;
    }

void CConsoleControl::ConstructL(const TRect& aClientRect)
    {
    iConsole=new(ELeave) CEikConsoleScreen;
    _LIT(KEikSec,"EikSec");
    iConsole->ConstructL(KEikSec,aClientRect.iTl, aClientRect.Size(),0,EEikConsWinInPixels);    
    }


CConsoleControl::~CConsoleControl()
    {
    delete iConsole;
    }

CConsoleBase& CConsoleControl::Console()
    {
    return *iConsole;
    }

void CConsoleControl::ActivateL()
// Mark control ready to draw
    {
    CCoeControl::ActivateL();
    iConsole->SetKeepCursorInSight(EFalse);
    iConsole->DrawCursor();
    iConsole->ConsoleControl()->SetFocus(ETrue, EDrawNow); 
    }

// CSettingsDialog: settings dialog
TBool CSettingsDialog::RunDlgLD(TConnectSettings& aConnectSettings)
    {
    CEikDialog* dialog=new(ELeave) CSettingsDialog(aConnectSettings);
    return (dialog->ExecuteLD(R_SECS_SETTINGS));    
    }

CSettingsDialog::CSettingsDialog(TConnectSettings& aConnectSettings)
: iConnectSettings(aConnectSettings)
    {
    }

void CSettingsDialog::PreLayoutDynInitL()
    {
    // Populate dialog with initial settings
    CEikEdwin* name=(CEikEdwin*)Control(EServerName);
    name->SetTextL(&iConnectSettings.iAddress);
    CEikEdwin* page=(CEikEdwin*)Control(EPage);
    TBuf<KSettingFieldWidth> temp;
    temp.Copy(iConnectSettings.iPage);
    page->SetTextL(&temp);
    CEikNumberEditor* port = (CEikNumberEditor*)Control(EPort);
    port->SetNumber(iConnectSettings.iPortNum);
    }

TBool CSettingsDialog::OkToExitL(TInt /*aButtonId*/)
    {
    // Store dialog input
    CEikEdwin* name=(CEikEdwin*)Control(EServerName);
    name->GetText(iConnectSettings.iAddress);
    CEikEdwin* page=(CEikEdwin*)Control(EPage);
    TBuf<KSettingFieldWidth> temp;
    page->GetText(temp);
    iConnectSettings.iPage.Copy(temp);
    CEikNumberEditor* port = (CEikNumberEditor*)Control(EPort);
    iConnectSettings.iPortNum = port->Number();

    return ETrue;
    }

//
// CSecAppUi: user interface command handling
//

// Construction functions
CSecAppUi::CSecAppUi(CSecEngine* aSecEngine)
        : iSecEngine(aSecEngine)
    {
    _LIT(KFile,"c:\\secsocout.txt");
    iOutputFileName = KFile;
    iConnectSettings.iPortNum = 443;
    }

void CSecAppUi::ConstructL()
// Set up control and engine
    {
    BaseConstructL();

    iConsoleControl=CConsoleControl::NewL(ClientRect());
    AddToStackL(iConsoleControl);
    iConsoleControl->ActivateL();

    iSecEngine -> SetConsole( iConsoleControl->Console() );
    _LIT(KStart,"\nChoose Connect from the menu to get a secure web page\n");
    iConsoleControl->Console().Printf(KStart);
    }


CSecAppUi::~CSecAppUi()
    {
    RemoveFromStack(iConsoleControl);
    delete iConsoleControl;
    }
    
void CSecAppUi::HandleCommandL(TInt aCommand)
// Command handling
    {
    switch (aCommand)
        {
    // Start
    case ECmdStart:
        if (CSettingsDialog::RunDlgLD(iConnectSettings))
            {
            User::LeaveIfError(iOutputFile.Replace(iEikonEnv->FsSession(),
                iOutputFileName,
                EFileWrite));
            iSecEngine -> SetOutputFile(iOutputFile);
            iSecEngine -> ConnectL(iConnectSettings);
            }
// This may be helpful for testing - www.fortify.net SSL test
        else
            {
            
            iConnectSettings.iAddress=_L(" 203.124.140.161");
            iConnectSettings.iPage=_L8("https://www.mail.mphasis.com");
//cgi-bin/ssl_2
            User::LeaveIfError(iOutputFile.Replace(iEikonEnv->FsSession(),
                iOutputFileName,
                EFileWrite));
            iSecEngine -> SetOutputFile(iOutputFile);
            iSecEngine -> ConnectL(iConnectSettings);
            }
        break;
    // Cancel
    case ECmdCancel:
        iSecEngine -> Cancel();
        break;
    // When Exit chosen, stop engine and quit
    case EEikCmdExit:
        iSecEngine -> Cancel();
        Exit();
    default:;
        }
    }

void CSecAppUi::DynInitMenuPaneL(TInt aResourceId, CEikMenuPane* aMenuPane)
    {
    if (aResourceId == R_CONS_FILE_MENU)
        {
        // Dim items appropriately according to whether in engine started or not
        aMenuPane->SetItemDimmed(ECmdStart,iSecEngine->InUse());
        aMenuPane->SetItemDimmed(ECmdCancel,!(iSecEngine->InUse()));
        }
    }

CSecDocument::CSecDocument(CEikApplication& aApp)
    : CEikDocument(aApp) { }

CSecDocument* CSecDocument::NewL(CEikApplication& aApp)
    {
    CSecDocument* self=new (ELeave) CSecDocument(aApp);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop();
    return self;
    }

void CSecDocument::ConstructL()
    {
    iSecEngine = CSecEngine::NewL();
    }
CSecDocument::~CSecDocument()
    {
    delete iSecEngine;
    }

CEikAppUi* CSecDocument::CreateAppUiL()
    {
    return(new(ELeave) CSecAppUi(iSecEngine));
    }

TUid CSecApplication::AppDllUid() const
    {
    return(KUidSecApp);
    }

CApaDocument* CSecApplication::CreateDocumentL()
    {
    return CSecDocument::NewL(*this);
    }

EXPORT_C CApaApplication* NewApplication()
    {
    return(new CSecApplication);
    }

GLDEF_C TInt E32Main()                        
    {
    return EikStart::RunApplication(NewApplication);
    }

//
// SecEngine.h
//
// Copyright (c) 2001 Symbian Ltd.  All rights reserved.

#ifndef __SECENGINE_H__
#define __SECENGINE_H__

#include <e32cons.h>
#include <c32comm.h>
#include <in_sock.h>
#include <securesocket.h>
#include <x509cert.h>

/** Number of chars allowed for address & page settings */
const TInt KSettingFieldWidth = 128;

/** Connection settings to access a server  */
struct TConnectSettings
    {
    /** Server address (as text) */
    TBuf<KSettingFieldWidth> iAddress;
    /** Server port */
    TInt iPortNum;
    /** Web page to get from the server */
    TBuf8<KSettingFieldWidth> iPage;
    };

/**
    Manages connection to a SSL web server.
*/
class CSecEngine : public CActive
    {
public:
/**
Allocates and constructs a new engine.
@return New object
*/
    static CSecEngine *NewL();
/**
Destructor.
*/
    ~CSecEngine();
/**
Initiates the connection to a server and the transaction

    @param aAddress Server address (e.g. www.symbian.com or dotted decimal format)

    @param aPortNum Server port for secure web (e.g. 443)

    @param aPage Web page to get from the server. The leading `/` should be included, e.g. /webpage.html.

    @param aCipherSuite Cipher suites that client will tell server it supports (decimal). This 
    should be in decimal, with 2 characters, ie for suites 3,7,8,9, this field would be 03070809.
    By entering a single `0` for this field, the SSL default cipher suites will be passed.

    @param aCipher Cipher suite that server is expected to use (decimal). This is compared with 
    actual cipher for pass/fail. If this field is 0, no comparisons with the actual cipher 
    suite used will be made.

*/
    void ConnectL( const TConnectSettings& aConnectSettings );
/**
Sets the console to write messages to

@param aConsole The console
*/
    void SetConsole( CConsoleBase& aConsole );

/**
Sets the (opened) file to write server response to

@param aOutputFile The file
*/
    void SetOutputFile( RFile& aOutputFile );

/**
Tests if the connection is in progress.

@return True if in progress else false
*/
    TBool InUse();

private:
    /** Engine states */
    enum TStates  
        {
        /** IP connection initiated */
        ESocketConnected,
        /** Setting the ciphers for a secure connection */
        ESettingCiphers,
        /** Secure socket request initiated */
        ESecureConnected,
        /** Send get page request to server */
        EGetRequestSent,
        /** Server has responded to request */
        EDataReceived,
        /** Connection closed down */
        EConnectionClosed
        };
    
private:
    /** Constructor. */
    CSecEngine();    
    /** Second phase constructor. */
    void ConstructL();

    // Methods from CActive
    /** Previous state has completed. */
    void RunL();
    /** Cancel request */
    void DoCancel();
    /** Handles a leave occurring in RunL(). */
    TInt RunError( TInt aError );
    
    // Handle particular engine states
    /** Attempts secure connection. */
    void MakeSecureConnectionL();
    /** Sends page request to server */   
    void MakePageRequestL();
    /** Start getting server's response to the request */
    void GetServerResponseL();
    /** Finish getting server's response */
    void ReadServerResponseL();
    /** Handle connection completed */
    void ConnectionClosed();

    /** Prints the name of the indicated cipher */
    void PrintCipherNameL(const TDes8& aBuf);
    /** Prints information about the server's cetificate */
    void PrintCertInfo(const CX509Certificate& aSource);

private:
    // Sockets objects
    /** The socket server */
    RSocketServ iSocketServ;
    /** Socket to make connection on */
    RSocket iSocket;
    /** For resolving DNS addresses */
    RHostResolver iHostResolver;
    /** Server address */
    TInetAddr iInetAddr;
    /** The secure socket interface */
    CSecureSocket* iTlsSocket;

    // Connection parameters
    const TConnectSettings* iConnectSettings;

    // Transfer buffers and counters
    /** Data sent buffer */
    TPtr8 iSndBuffer;
    /** #bytes sent */
    TSockXfrLength iBytesSent;
    /** Data received buffer */
    TPtr8 iRcvBuffer;
    /** #bytes received */
    TInt iTotalBytesRead;

    /** For retries, after a delay */
    RTimer iTimer;

    /** Output console */
    CConsoleBase *iConsole;
    /** Output file */
    RFile* iOutputFile;

    // Flags and state
    /** True if the transation completed successfully */
    TBool       iSuccess;
    /** True if success on first attempt */
    TBool   iFirstRunFlag;
    /** True if connection is in progress */
    TBool   iInUse;
    /** Engine state (a TStates value) */
    TInt    iRunState;
    };

#endif

// SecureSockets.h
//
// Copyright (c) 2001 Symbian Ltd.  All rights reserved.
//

#include <basched.h>
#include <eikenv.h>
#include <coecntrl.h>
#include <eikappui.h>
#include <e32keys.h>
#include <eikconso.h>
#include <eikapp.h>
#include <eikdoc.h>
#include <eikon.rsg>
#include <eikinfo.h>
#include <eikon.hrh>

#include <SecureSockets.rsg>
#include "secengine.h"

#ifndef _SECAPP_H_
#define _SECAPP_H_


/** Application UID */
const TUid KUidSecApp = {0x101F4115};

/** 
    Console-type control
*/
class CConsoleControl : public CCoeControl
    {
public:
    static CConsoleControl* NewL(const TRect& aClientRect);
    ~CConsoleControl();
    void ConstructL(const TRect& aClientRect);
    CConsoleBase& Console();

    // Override CCoeControl 
    void ActivateL();

protected:
    CConsoleControl() {}

private:
    CEikConsoleScreen* iConsole;   // Standard console control
    };

/** 
    Dialog that allows user to specify web page to securely connect to
 */
class CSettingsDialog: public CEikDialog
    {
public:
    /**
    Creates and runs the settings dialog.
    @return True if settings confirmed
    @param aConnectSettings The settings, on return the dialog values
    */
    static TBool RunDlgLD(TConnectSettings& aConnectSettings);

private:
    /**
    Constructor.
    @param aConnectSettings The settings
    */
    CSettingsDialog(TConnectSettings& aConnectSettings);

    // From CEikDialog
    /** Populate dialog with initial settings */
    void PreLayoutDynInitL();
    /** Store dialog input */
    TBool OkToExitL(TInt aButtonId);

private:
    /** The settings */
    TConnectSettings& iConnectSettings;
    };

/**
    User interface command handling
*/
class CSecAppUi : public CEikAppUi
    {
public:
    CSecAppUi(CSecEngine* aSecEngine);
    void ConstructL();
    ~CSecAppUi();

private: 
    // Override CEikAppUi
    void HandleCommandL(TInt aCommand);
    void DynInitMenuPaneL(TInt aResourceId, CEikMenuPane* aMenuPane);

private:
    CConsoleControl* iConsoleControl;
    CSecEngine* iSecEngine;
    TConnectSettings iConnectSettings;

    RFile iOutputFile;
    TFileName iOutputFileName;
    };

/**
    Document class, which owns the engine
*/
class CSecDocument : public CEikDocument
    {
public:
    CSecDocument(CEikApplication& aApp);
    static CSecDocument* NewL(CEikApplication& aApp);
    ~CSecDocument();
    void ConstructL();
private: 
    // Override CApaDocument
    CEikAppUi* CreateAppUiL();
private: 
    CSecEngine* iSecEngine; // Document owns the engine
    };

/**
    Application class
*/
class CSecApplication : public CEikApplication
    {
private: // from CApaApplication
    CApaDocument* CreateDocumentL();
    TUid AppDllUid() const;
    };
#endif

// SecureSockets.hrh
//
// Copyright (c) 2001 Symbian Ltd.  All rights reserved.
//

#ifndef __SEC_HRH__
#define __SEC_HRH__

/** Settings dialog fields */
enum
    {
    EServerName,
    EPort,
    EPage
    };

/** UI commands */
enum
    {
    ECmdStart = 1000,
    ECmdCancel
    };

/** Maximum text field width */
#define EFieldMax 128
/** Displayed text field width */
#define EFieldWidth 10

#endif

// BLD.INF
// Component description file
//
// Copyright (c) 2000 Symbian Ltd.  All rights reserved.

PRJ_MMPFILES
SecureSockets.mmp

/ SecureSockets.mmp
//
// Copyright (c) 2000-2005 Symbian Software Ltd.  All rights reserved.

TARGET      SecureSockets.exe
TARGETTYPE  exe
UID         0x100039CE 0x101F4115

VENDORID   0x70000001
CAPABILITY   All -TCB

SOURCEPATH      .
SOURCE          SecureSockets.cpp SecEngine.cpp

START RESOURCE SecureSockets.rss          
TARGET          SecureSockets.rsc
TARGETPATH      \Resource\Apps
HEADER
LANG 01       // Build English language versions
END

start resource    SecureSockets_reg.rss        
targetpath         \private\10003a3f\apps
end

// To support localisation for the UI applicatons
start resource SecureSockets_loc.rss  
lang           01
end

USERINCLUDE    .
SYSTEMINCLUDE   \Epoc32\include
SYSTEMINCLUDE  \epoc32\include\techview

// Base libraries
LIBRARY         euser.lib efsrv.lib 
// UI libraries
LIBRARY         apparc.lib cone.lib eikcore.lib  eikcoctl.lib eikdlg.lib eikctl.lib
// Comms and security libraries
LIBRARY         esock.lib insock.lib securesocket.lib
LIBRARY        crypto.lib

// SecureSockets.RSS
//
// Copyright (c) 2001 Symbian Ltd.  All rights reserved.
//

NAME SECS

#include <eikon.rh>
#include <eikon.rsg>

#include "SecureSockets.hrh"

RESOURCE RSS_SIGNATURE { }

RESOURCE TBUF16 { buf=""; }

RESOURCE EIK_APP_INFO { hotkeys=r_cons_hotkeys; menubar=r_cons_menubar; }

RESOURCE HOTKEYS r_cons_hotkeys
    {
    control=
        {
        HOTKEY { command=EEikCmdExit; key='e'; },
        HOTKEY { command=ECmdStart; key='s'; },
        HOTKEY { command=ECmdCancel; key='x'; }
        };
    }

RESOURCE MENU_BAR r_cons_menubar
    {
    titles=
        {
        MENU_TITLE { menu_pane=r_cons_file_menu; txt="Socket"; }
        };
    }

RESOURCE MENU_PANE r_cons_file_menu
    {
    items=
        {
       MENU_ITEM 
            { 
            command=ECmdStart; 
            txt="Connect"<KEllipsis>; 
            },
       MENU_ITEM 
            { 
            command=ECmdCancel; 
            txt="Cancel"; 
            },
       MENU_ITEM 
            { 
            command=EEikCmdExit; 
            txt="Exit"; 
            }
        };
    }

RESOURCE DIALOG r_secs_settings
    {
    title="Connection settings";
    flags=EEikDialogFlagWait;
    buttons=R_EIK_BUTTONS_CANCEL_OK;
    items=
        {
        DLG_LINE
            {
            prompt="Server name";
            type=EEikCtEdwin;
            id=EServerName;
            control=EDWIN
                {
                maxlength=EFieldMax;
                width=EFieldWidth;
                }; 
            },
        DLG_LINE
            {
            prompt="Port";
            type=EEikCtNumberEditor;
            id=EPort;
            control=NUMBER_EDITOR
                {
                min=1;
                max=999;
                };
            },
        DLG_LINE
            {
            prompt="Page";
            type=EEikCtEdwin;
            id=EPage;
            control=EDWIN
                {
                maxlength=EFieldMax;
                width=EFieldWidth;
                }; 
            }
        };
    }

// SecureSockets_loc.RSS
//
// Copyright (c) 2005 Symbian Software Ltd.  All rights reserved.
//

#include <appinfo.rh>
   
RESOURCE LOCALISABLE_APP_INFO
{
short_caption = "SecureSockets";
caption_and_icon =
    {
    CAPTION_AND_ICON_INFO
        {
        caption = "SecureSockets";
        number_of_icons = 0; // each icon must be a bitmap/mask pair
        }
    };
}     

// SecureSockets_reg.RSS
//
// Copyright (c) 2005-2005 Symbian Software Ltd.  All rights reserved.
//

#include <appinfo.rh>

UID2 KUidAppRegistrationResourceFile
UID3 0x101F4115
RESOURCE APP_REGISTRATION_INFO
 { 
 app_file = SecureSockets;
 localisable_resource_file="\\resource\\apps\\SecureSockets_loc.rss";
 hidden=KAppNotHidden;
 embeddability=KAppNotEmbeddable;
 newfile=KAppDoesNotSupportNewFile;
 launch=KAppLaunchInForeground;
 }


Description

This example demonstrates how a secure sockets (SSL/TLS) connection can be made and used. It allows the user to specify a web page to retrieve from a secure HTTP server, then makes a secure connection and gets the page.

The central class is an active object, CSecEngine. The user of this class initiates a connection by calling Connect(), specifying the server, port, and page to get. CSecEngine then begins executing a simple state machine, where each step makes a particular asynchronous request. When a step's request completes, CSecEngine::RunL() calls the function for the next step. The steps are:

[Top]


Usage

Note: before running the program, set up comms settings so that the required network connections can be made, and test these settings, for example by retrieving a web page using the platform's web browser.

The program's main window is a console that logs the connection activity. Initiating or stopping a connection is done through the menu's Connect and Cancel commands.

When you choose Connect, a dialog appears prompting you for:

For a successful connection, the program's output is as follows: