www.pudn.com > sockets.rar > socketsengine.cpp


/* Copyright (c) 2004, Nokia. All rights reserved */ 
 
 
// INCLUDE FILES 
#include  
#include  
#include  
#include  
 
#include "SocketsEngine.h" 
#include "TimeOutTimer.h" 
#include "SocketsReader.h" 
#include "SocketsWriter.h" 
#include "Sockets.pan" 
#include "UINotifier.h" 
 
// STATIC MEMBER INITIALISATIONS 
const TInt CSocketsEngine::KTimeOut = 30000000; // 30 seconds time-out 
const TInt CSocketsEngine::KDefaultPortNumber = 7; 
 
// ========================= MEMBER FUNCTIONS ================================== 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::NewL() 
// Two-phased constructor. 
// ----------------------------------------------------------------------------- 
// 
CSocketsEngine* CSocketsEngine::NewL( MUINotifier& aConsole ) 
    { 
    CSocketsEngine* self = CSocketsEngine::NewLC( aConsole ); 
    CleanupStack::Pop( self ); 
    return self; 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::NewLC() 
// Two-phased constructor. 
// ----------------------------------------------------------------------------- 
// 
CSocketsEngine* CSocketsEngine::NewLC( MUINotifier& aConsole ) 
    { 
    CSocketsEngine* self = new ( ELeave ) CSocketsEngine( aConsole ); 
    CleanupStack::PushL( self ); 
    self->ConstructL(); 
    return self; 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::CSocketsEngine() 
// C++ default constructor can NOT contain any code, that might leave. 
// ----------------------------------------------------------------------------- 
// 
CSocketsEngine::CSocketsEngine( MUINotifier& aConsole ) 
: CActive( EPriorityStandard ), 
  iConsole( aConsole ), 
  iPort( KDefaultPortNumber ), 
  iServerName( KDefaultServerName ) 
    { 
    // No implementation required 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::ConstructL() 
// Symbian 2nd phase constructor can leave. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::ConstructL() 
    { 
    ChangeStatus( ENotConnected ); 
 
    // Start a timer 
    iTimer = CTimeOutTimer::NewL( EPriorityHigh, *this ); 
    CActiveScheduler::Add( this ); 
 
    // Open channel to Socket Server 
    User::LeaveIfError( iSocketServ.Connect() ); 
 
    // Create socket read and write active objects 
    iSocketsReader = CSocketsReader::NewL( *this, iSocket ); 
    iSocketsWriter = CSocketsWriter::NewL( *this, iSocket ); 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::~CSocketsEngine() 
// Destructor. 
// ----------------------------------------------------------------------------- 
// 
CSocketsEngine::~CSocketsEngine() 
    { 
    Cancel(); 
 
    delete iSocketsReader; 
    iSocketsReader = NULL; 
 
    delete iSocketsWriter; 
    iSocketsWriter = NULL; 
 
    delete iTimer; 
    iTimer = NULL; 
 
    iSocketServ.Close(); 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::ConnectL() 
// Initiates connection of socket, using iServerName and iPort. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::ConnectL() 
    { 
    // Initiate connection process 
    if ( iEngineStatus == ENotConnected ) 
        { 
        TInetAddr addr; 
        if ( addr.Input( iServerName ) == KErrNone ) 
            { 
            // server name is already a valid ip address 
            ConnectL( addr.Address() ); 
            } 
        else // need to look up name using dns 
            { 
            // Initiate DNS 
            User::LeaveIfError( iResolver.Open( iSocketServ, 
                                                KAfInet, 
                                                KProtocolInetUdp ) ); 
            // DNS request for name resolution 
            iResolver.GetByName( iServerName, iNameEntry, iStatus ); 
 
            ChangeStatus( ELookingUp ); 
            // Request time out 
            iTimer->After( KTimeOut ); 
            SetActive(); 
            } 
        } 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::ConnectL() 
// Initiates a connect operation on a socket. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::ConnectL( TUint32 aAddr ) 
    { 
    // Initiate attempt to connect to a socket by IP address 
    if ( iEngineStatus == ENotConnected ) 
        { 
        // Open a TCP socket 
        User::LeaveIfError( iSocket.Open( iSocketServ, 
                                          KAfInet, 
                                          KSockStream, 
                                          KProtocolInetTcp ) ); 
 
        // Set up address information 
        iAddress.SetPort( iPort ); 
        iAddress.SetAddress( aAddr ); 
 
        // Initiate socket connection 
        iSocket.Connect( iAddress, iStatus ); 
        ChangeStatus( EConnecting ); 
 
        // Start a timeout 
        iTimer->After( KTimeOut ); 
 
        SetActive(); 
        } 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::Disconnect() 
// Disconnects socket. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::Disconnect() 
    { 
    __ASSERT_ALWAYS( iEngineStatus == EConnected, 
                     User::Panic( KPanicSocketsEngine, ESocketsBadState ) ); 
 
    // Cancel all outstanding operations 
    // Since we are connected, the only possibilities are read and write 
    iSocketsReader->Cancel(); 
    iSocketsWriter->Cancel(); 
 
    iSocket.Close(); 
    ChangeStatus( ENotConnected ); 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::DoCancel() 
// Cancels any outstanding operation. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::DoCancel() 
    { 
    iTimer->Cancel(); 
 
    // Cancel appropriate request to socket 
    switch ( iEngineStatus ) 
        { 
        case EConnecting: 
            iSocket.CancelConnect(); 
            iSocket.Close(); 
            break; 
        case ELookingUp: 
            // Cancel look up attempt 
            iResolver.Cancel(); 
            iResolver.Close(); 
            break; 
        default: 
            User::Panic( KPanicSocketsEngine, ESocketsBadStatus ); 
            break; 
        } 
 
    ChangeStatus( ENotConnected ); 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::WriteL() 
// Writes data to socket. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::WriteL( const TDesC8& aData ) 
    { 
    if ( iEngineStatus == EConnected ) 
        { 
        iSocketsWriter->IssueWriteL( aData ); 
        } 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::Read() 
// Initiates read of data from socket. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::Read() 
    { 
    if ( ( iEngineStatus == EConnected ) && ( !iSocketsReader->IsActive() ) ) 
        { 
        iSocketsReader->Start(); 
        } 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::RunL() 
// Called when operation completes. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::RunL() 
    { 
    // Active object request complete handler. 
    // iEngineStatus flags what request was made, so its 
    // completion can be handled appropriately 
    iTimer->Cancel(); // Cancel TimeOut timer before completion 
 
    switch( iEngineStatus ) 
        { 
        case EConnecting: 
            // IP connection request 
            if ( iStatus == KErrNone ) 
                // Connection completed successfully 
                { 
                ChangeStatus( EConnected ); 
                Read(); //Start CSocketsReader Active object 
                } 
            else 
                { 
                iSocket.Close(); 
 
                // Read localized error message from resource file 
                HBufC* connectionError = 
                    StringLoader::LoadLC( R_SOCK_CONN_FAILED ); 
                iConsole.ErrorNotify( *connectionError, iStatus.Int() ); 
                CleanupStack::PopAndDestroy(); // connectionError 
                ChangeStatus( ENotConnected ); 
                } 
            break; 
        case ELookingUp: 
            iResolver.Close(); 
            if ( iStatus == KErrNone ) 
                { 
                // DNS look up successful 
                iNameRecord = iNameEntry(); 
 
                // Extract domain name and IP address from name record 
                HBufC* domainName = 
                    StringLoader::LoadLC( R_SOCK_DOMAIN_NAME ); 
                Print( *domainName ); 
                CleanupStack::PopAndDestroy(); // domainName 
                Print( iNameRecord.iName ); 
 
                TBuf<15> ipAddr; 
                TInetAddr::Cast( iNameRecord.iAddr ).Output( ipAddr ); 
 
                HBufC* ipAddress = StringLoader::LoadLC( R_SOCK_IP_ADDRESS ); 
                Print( *ipAddress ); 
                CleanupStack::PopAndDestroy(); // domainName 
 
                Print( ipAddr ); 
                Print( KStrNewLine ); 
 
                // And connect to the IP address 
                ChangeStatus( ENotConnected ); 
                ConnectL( TInetAddr::Cast( iNameRecord.iAddr ).Address() ); 
                } 
            else 
                { 
                // DNS lookup failed 
                HBufC* dnsError = StringLoader::LoadLC( R_SOCK_DNS_FAILED ); 
                iConsole.ErrorNotify( *dnsError, iStatus.Int() ); 
                CleanupStack::PopAndDestroy(); // dnsError 
                ChangeStatus( ENotConnected ); 
                } 
            break; 
        default: 
            User::Panic( KPanicSocketsEngine, ESocketsBadStatus ); 
            break; 
 
        }; 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::TimerExpired() 
// The function to be called when a timeout occurs. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::TimerExpired() 
    { 
    Cancel(); 
 
    TBuf timeOutError; 
    StringLoader::Load(timeOutError, R_SOCK_TIMEOUT ); 
    iConsole.ErrorNotify( timeOutError, KErrTimedOut ); 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::ReportError() 
// Report a communication error. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::ReportError( MEngineNotifier::TErrorType aErrorType, 
                                  TInt aErrorCode ) 
    { 
    // No recovery or retries are attempted in this example so we just 
    // disconnect and inform the user 
    Disconnect(); 
    TBuf errorMessage; 
    switch ( aErrorType ) 
        { 
        case MEngineNotifier::EDisconnected: 
            StringLoader::Load( errorMessage, R_SOCK_DISCONNECTED ); 
            iConsole.ErrorNotify( errorMessage, aErrorCode ); 
            break; 
        case MEngineNotifier::EGeneralReadError: 
            StringLoader::Load( errorMessage, R_SOCK_READ_ERROR ); 
            iConsole.ErrorNotify( errorMessage, aErrorCode ); 
            break; 
        case MEngineNotifier::ETimeOutOnWrite: 
            StringLoader::Load( errorMessage, R_SOCK_WRITE_TIMEOUT ); 
            iConsole.ErrorNotify( errorMessage, aErrorCode ); 
            break; 
        case MEngineNotifier::EGeneralWriteError: 
            StringLoader::Load( errorMessage, R_SOCK_GENERAL_WRITE_ERROR ); 
            iConsole.ErrorNotify( errorMessage, aErrorCode ); 
            break; 
        default: 
            User::Panic( KPanicSocketsEngine, ESocketsBadStatus ); 
            break; 
        } 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::ResponseReceived() 
// Data has been received on the socket and read into a buffer. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::ResponseReceived( const TDesC8& aBuffer ) 
    { 
    iConsole.PrintNotify( aBuffer ); 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::ChangeStatus() 
// Handles a change in this object's status. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::ChangeStatus( TSocketsEngineState aNewStatus ) 
    { 
    TBuf statusInfo; 
    // Update the status ( and the status display ) 
    switch ( aNewStatus ) 
        { 
        case ENotConnected: 
            StringLoader::Load( statusInfo, R_SOCK_NOT_CONNECTED ); 
            iConsole.SetStatus( statusInfo ); 
            break; 
        case EConnecting: 
            StringLoader::Load( statusInfo, R_SOCK_CONNECTING ); 
            iConsole.SetStatus( statusInfo ); 
            break; 
        case EConnected: 
            StringLoader::Load( statusInfo, R_SOCK_CONNECTED ); 
            iConsole.SetStatus( statusInfo ); 
            break; 
        case ELookingUp: 
            StringLoader::Load( statusInfo, R_SOCK_LOOKING_UP ); 
            iConsole.SetStatus( statusInfo ); 
            break; 
        default: 
            User::Panic( KPanicSocketsEngine, ESocketsBadStatus ); 
            break; 
        } 
    iEngineStatus = aNewStatus; 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::Print() 
// Displays text on the console. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::Print( const TDesC& aDes ) 
    { 
    iConsole.PrintNotify( aDes, CEikGlobalTextEditor::EItalic ); 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::SetServerName() 
// Sets name of server to connect to. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::SetServerName( const TDesC& aName ) 
    { 
    iServerName.Copy( aName ); 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::ServerName() 
// Gets server name. 
// ----------------------------------------------------------------------------- 
// 
const TDesC& CSocketsEngine::ServerName() const 
    { 
    return iServerName; 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::SetPort() 
// Sets port number to connect to. 
// ----------------------------------------------------------------------------- 
// 
void CSocketsEngine::SetPort( TInt aPort ) 
    { 
    iPort = aPort; 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::Port() 
// Gets port number. 
// ----------------------------------------------------------------------------- 
// 
TInt CSocketsEngine::Port() const 
    { 
    return iPort; 
    } 
 
// ----------------------------------------------------------------------------- 
// CSocketsEngine::Connected() 
// Checks if socket is fully connected. 
// ----------------------------------------------------------------------------- 
// 
TBool CSocketsEngine::Connected() const 
    { 
    return ( iEngineStatus == EConnected ); 
    } 
 
// End of File