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;
}
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:
MakeSecureConnectionL()
: creates a
CSecureSocket
object, and initiates a secure connection by calling
CSecureSocket::StartClientHandshake()
MakePageRequestL()
: sends the get page request to the
server using CSecureSocket::Send()
GetServerResponseL()
: logs the protocol
(CSecureSocket::Protocol()
), cipher suite
(CSecureSocket::CurrentCipherSuite()
), and server certificate
(CSecureSocket::ServerCert()
), and then begins receiving data from
the server using CSecureSocket::Recv()
ReadServerResponseL()
: examines data received from the
server, and concludes that either the transaction is complete, or that
CSecureSocket::Recv()
should be called again to retrieve more data
ConnectionClosed()
: closes the various sockets
resources when the transaction is complete
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:
the HTTP server to connect to: this can be a DNS-resolvable name (e.g. www.example.net) or a dotted-decimal address (e.g. 10.192.193.194).
the port, which defaults to 443, the usual port for secure HTTP
the page name, for example, \example.html. Note the leading slash.
For a successful connection, the program's output is as follows:
A message confirming the server and page being connected to. Depending on your comms database settings, you may be queried to confirm the connection.
A message "Making secure connection" when the server has been connected to
Messages reporting the protocol, cipher suite, and content of the server certificate. You may be queried to accept a non-trusted certificate.
One or more "Receiving server response" messages as data is received from the server.
A "Transaction complete: bytes received <number>" message when the transaction is complete.
The data read from the server (i.e. the requested web page) is
written to a file c:\secsocout.txt
.