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