examples/Networking/TcpIp/EchoClientEngine/ECHOENG.CPP

00001 /*
00002 Copyright (c) 2000-2010 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.
00003 
00004 Redistribution and use in source and binary forms, with or without
00005 modification, are permitted provided that the following conditions are met:
00006 
00007 * Redistributions of source code must retain the above copyright notice, this
00008   list of conditions and the following disclaimer.
00009 * Redistributions in binary form must reproduce the above copyright notice,
00010   this list of conditions and the following disclaimer in the documentation
00011   and/or other materials provided with the distribution.
00012 * Neither the name of Nokia Corporation nor the names of its contributors
00013   may be used to endorse or promote products derived from this software
00014   without specific prior written permission.
00015 
00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00017 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00018 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00020 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00021 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00022 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00023 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00024 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00025 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 
00027 Description: Defines CEchoEngine, CEchoRead, CEchoWrite, CTimeOutTimer  
00028 */
00029 
00030 
00031 
00032 #include "ECHOENG.H"
00033 
00034 // 50 seconds time-out
00035 const TInt KTimeOut = 50000000; 
00036                                          
00037 /*
00038  CEchoEngine: main engine class for connection and shutdown
00039 */
00040 EXPORT_C CEchoEngine::CEchoEngine() : CActive(EPriorityStandard)
00041         {
00042         }
00043 
00044 EXPORT_C CEchoEngine* CEchoEngine::NewL(MUINotify* aConsole)
00045         {
00046         CEchoEngine* self = NewLC(aConsole);
00047         CleanupStack::Pop();
00048         return self;
00049         }
00050 
00051 EXPORT_C CEchoEngine* CEchoEngine::NewLC(MUINotify* aConsole)
00052         {
00053         CEchoEngine* self = new(ELeave) CEchoEngine;
00054         CleanupStack::PushL(self);
00055         self->ConstructL(aConsole);
00056         return self;
00057         }
00058 /*
00059  Constructs object, and opens a socket 
00060 */
00061 EXPORT_C void CEchoEngine::ConstructL(MUINotify* aConsole)
00062         {
00063         iConsole = aConsole;
00064         iEngineStatus = EComplete;
00065 
00066         iTimeOut = KTimeOut; 
00067         iTimer = CTimeOutTimer::NewL(EPriorityHigh, *this);
00068         CActiveScheduler::Add(this); 
00069 
00070         // Open channel to Socket Server
00071         User::LeaveIfError(iSocketServ.Connect());
00072         // Open a TCP socket
00073         User::LeaveIfError(iEchoSocket.Open(iSocketServ, KAfInet, KSockStream, KProtocolInetTcp));
00074 
00075         iEchoRead = new CEchoRead(&iEchoSocket, aConsole);
00076         iEchoWrite = CEchoWrite::NewL(&iEchoSocket, aConsole);
00077         }
00078 
00079 void CEchoEngine::DoCancel()
00080 // Cancel asychronous requests
00081         {
00082         iTimer->Cancel();
00083 
00084         // Cancel appropriate request to socket
00085         switch (iEngineStatus)
00086                 {
00087         case EConnecting:
00088                 iEchoSocket.CancelConnect();
00089                 break;
00090         case ELookingUp:
00091                 // Cancel look up attempt
00092                 iResolver.Cancel();
00093                 iResolver.Close();
00094                 break;
00095         default:;
00096                 }
00097         }
00098 /*
00099  Connect to an Echo Socket by IP address        
00100 */
00101 EXPORT_C void CEchoEngine::ConnectTo(TUint32 aAddr)
00102         {
00103         // port number for test purposes - may need to be changed
00104         iAddress.SetPort(7);
00105         iAddress.SetAddress(aAddr);
00106         iEchoSocket.Connect(iAddress, iStatus);
00107         iEngineStatus = EConnecting;
00108         SetActive();
00109         iTimer->After(iTimeOut);
00110         }
00111 
00112 EXPORT_C void CEchoEngine::ConnectL(const TDesC& aServerName)
00113         // Connect to an Echo socket by hostname
00114         {
00115         // Initiate DNS
00116         User::LeaveIfError(iResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp));
00117         // DNS request for name resolution
00118         iResolver.GetByName(aServerName, iNameEntry, iStatus);
00119         
00120         iEngineStatus=ELookingUp;
00121         // Request time out
00122         iTimer->After(iTimeOut);
00123         SetActive();
00124         }
00125 
00126 EXPORT_C void CEchoEngine::TestGetByAddrL(TUint32 aAddr)
00127         // Looks up hostname, and then connects to an Echo socket 
00128         {
00129         // Initiate DNS
00130         User::LeaveIfError(iResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp));
00131         // DNS request for address lookup
00132         iAddress.SetAddress(aAddr);
00133         iResolver.GetByAddress(iAddress, iNameEntry, iStatus);
00134 
00135         iEngineStatus=ELookingUp;
00136         // Request time out
00137         iTimer->After(iTimeOut);
00138         SetActive();
00139         }
00140 /*
00141 Exported function wrapping call to CEchoWrite: writes character to socket
00142 */
00143 EXPORT_C void CEchoEngine::Write(TChar aChar)
00144         {
00145         /* 
00146         In this simple implementation, if iEchoWrite is already active, ignore call.
00147         Full implementation would buffer data 
00148         */
00149         if ((iEngineStatus == EConnected) && !iEchoWrite->IsActive())
00150                 iEchoWrite->IssueWrite(aChar);
00151         }
00152 /*
00153 Exported function wrapping call to CEchoRead: reads character from socket
00154 */      
00155 EXPORT_C void CEchoEngine::Read()
00156         {
00157         if ((iEngineStatus == EConnected)&&(!iEchoRead->IsActive())) 
00158                 iEchoRead->IssueRead();
00159         }
00160 
00161 /*
00162  Active object request complete handler.
00163  iEngineStatus flags what request was made, so its
00164  completion can be handled appropriately
00165 */
00166 void CEchoEngine::RunL()
00167         {
00168         // Cancel TimeOut timer before completion
00169         iTimer->Cancel(); 
00170         _LIT(KConnecting,"\n<CEchoEngine> Connecting\n");
00171         _LIT(KConnectionFailed,"\n<CEchoEngine> Connection failed");
00172         _LIT(KDNSFailed,"\n<CEchoEngine> DNS lookup failed");
00173         _LIT(KTimedOut,"\n<CEchoEngine> Timed out\n");
00174         _LIT(KDomainName,"\nDomain name = ");
00175         _LIT(KIPAddress,"\nIP address = ");
00176 
00177         TBuf<15> ipAddr;
00178 
00179         switch(iEngineStatus)
00180                 {
00181         case EConnecting:
00182                 // IP connection request
00183                 if (iStatus == KErrNone)
00184                 // Connection completed sucessfully
00185                         {
00186                         iConsole->PrintNotify(KConnecting);
00187                         iEngineStatus = EConnected;
00188                         //Start CEchoRead Active object 
00189                         Read(); 
00190                         }
00191                 else
00192                         {
00193                         iEngineStatus = EConnectFailed;
00194                         iConsole->ErrorNotifyL(KConnectionFailed, iStatus.Int());
00195                         }
00196                 break;
00197         case ETimedOut:
00198                 // Timeout request
00199                 iConsole->ErrorNotifyL(KTimedOut, KErrTimedOut);
00200                 break;
00201         case ELookingUp:
00202                 iResolver.Close();
00203                 if (iStatus == KErrNone)
00204                 // DNS look up successful
00205                         {
00206                         iNameRecord = iNameEntry();
00207                         // Extract domain name and IP address from name record
00208                         iConsole->PrintNotify(KDomainName);
00209                         iConsole->PrintNotify(iNameRecord.iName);
00210                         TInetAddr::Cast(iNameRecord.iAddr).Output(ipAddr);
00211                         iConsole->PrintNotify(KIPAddress);
00212                         iConsole->PrintNotify(ipAddr);
00213                         // And connect to the IP address
00214                         ConnectTo(TInetAddr::Cast(iNameRecord.iAddr).Address());
00215                         }
00216                 else
00217                         {       
00218                         iStatus = ELookUpFailed;
00219                         iConsole->ErrorNotifyL(KDNSFailed, iStatus.Int());
00220                         }
00221                 break;
00222 
00223         default:;
00224                 };
00225         }
00226 
00227 CEchoEngine::~CEchoEngine()
00228         {
00229         delete iEchoRead;
00230         delete iEchoWrite;
00231         delete iTimer;
00232         iEchoSocket.Close();
00233         iSocketServ.Close();
00234         }
00235 
00236 /*
00237  Implements MTimeOutNotify: called when timeout expired
00238 */
00239 void CEchoEngine::TimerExpired()
00240         {
00241         Cancel();
00242         iEngineStatus = ETimedOut;
00243         TRequestStatus* p=&iStatus;             
00244         SetActive();
00245         User::RequestComplete(p, ETimedOut);
00246         }
00247 
00248 /*
00249  Shutdown connection request
00250 */
00251 EXPORT_C void CEchoEngine::Stop()
00252         {
00253         _LIT(KETerminate,"\n<CEchoEngine> Terminating\n");
00254 
00255         iConsole->PrintNotify(KETerminate);
00256 
00257         switch (iEngineStatus)
00258                 {
00259         case EConnected:
00260                 // Stop live connection
00261                 iEchoRead->Cancel();
00262                 iEchoWrite->Cancel();
00263                 break;
00264         case EConnecting:
00265         case ELookingUp:
00266                 // if request to CEchoEngine, then stop it
00267                 Cancel();
00268                 break;
00269         default:;
00270                 }
00271         }
00272 
00273 
00274 CEchoRead::CEchoRead(RSocket* aSocket, MUINotify* aConsole) 
00275 :CActive(EPriorityStandard), iEchoSocket(aSocket), iConsole(aConsole)
00276         {
00277         CActiveScheduler::Add(this);
00278         }
00279 
00280 
00281 /*
00282  Cancel asychronous read request
00283 */
00284 void CEchoRead::DoCancel()
00285         {
00286         iEchoSocket->CancelRead();
00287         }
00288 /*
00289  Active object request complete handler
00290 */
00291 void CEchoRead::RunL()
00292         {
00293         if (iStatus == KErrNone)
00294                 // Character has been read from socket
00295                 {
00296                 _LIT(KDot,".");
00297                 iConsole->PrintNotify(KDot);
00298                 TBuf16<1> Buffer;
00299                 Buffer.Copy(iBuffer);
00300                 iConsole->PrintNotify(Buffer);
00301                 IssueRead();
00302                 }
00303         else
00304                 {
00305                 // Error: pass it up to user interface
00306                 _LIT(KCEchoReadError,"\nCEchoRead error");
00307                 iConsole->ErrorNotifyL(KCEchoReadError, iStatus.Int());
00308                 }       
00309         }
00310 /*
00311  Read data from a stream socket
00312 */
00313 void CEchoRead::IssueRead()
00314         {
00315         if (!IsActive())
00316                 {
00317                 iEchoSocket->Recv(iBuffer, 0, iStatus);
00318                 SetActive();
00319                 }
00320         }
00321 /*
00322  This function is not actually used -
00323  It shows how to read data from a datagram socket 
00324 */
00325 void CEchoRead::IssueRecvFrom(TInetAddr &aAddr)
00326 
00327         {
00328         iEchoSocket->RecvFrom(iBuffer,aAddr,NULL,iStatus);
00329         SetActive();
00330         };
00331 
00332 /*
00333  CEchoWrite: active object wrapping comms write requests
00334 */
00335 CEchoWrite::CEchoWrite() : CActive(EPriorityStandard)
00336         {
00337 
00338         };
00339 
00340 CEchoWrite* CEchoWrite::NewL(RSocket* aSocket, MUINotify* aConsole)
00341         {
00342         CEchoWrite* self = NewLC(aSocket, aConsole);
00343         CleanupStack::Pop();
00344         return self;
00345         };
00346 
00347 CEchoWrite* CEchoWrite::NewLC(RSocket* aSocket, MUINotify* aConsole)
00348         {
00349         CEchoWrite* self = new(ELeave) CEchoWrite;
00350         CleanupStack::PushL(self);
00351         self->ConstructL(aSocket, aConsole);
00352         return self;
00353         };
00354 
00355 /*
00356 ConstructL function - adds the active object to the Scheduler
00357 */      
00358 void CEchoWrite::ConstructL(RSocket* aSocket, MUINotify* aConsole)
00359         {
00360         iEchoSocket = aSocket;
00361         iConsole = aConsole;
00362         CActiveScheduler::Add(this);
00363 
00364         iTimeOut = KTimeOut; 
00365         iTimer = CTimeOutTimer::NewL(10, *this);
00366         iWriteStatus = EWaiting;
00367         };
00368 
00369 CEchoWrite::~CEchoWrite()
00370         {
00371         delete iTimer;
00372         }
00373 /*
00374 Cancels asychronous write request
00375 */
00376 void CEchoWrite::DoCancel()
00377         {       
00378         iEchoSocket->CancelWrite();
00379         };
00380 /*
00381  Implements MTimeOutNotify: called when timeout expired
00382 */
00383 void CEchoWrite::TimerExpired()
00384         {
00385         Cancel();
00386         iWriteStatus = ETimedOut;
00387         TRequestStatus* p=&iStatus;             
00388         SetActive();
00389         User::RequestComplete(p, ETimedOut);
00390         }
00391 /*
00392  Active object request complete handler
00393 */
00394 void CEchoWrite::RunL()
00395         {
00396         if (iStatus == KErrNone)
00397                 {
00398                 _LIT(KWriteOperationTimedOut,"\nWrite operation timed out");
00399                 switch(iWriteStatus)
00400                         {
00401                 // Character has been written to socket
00402                 case ESending:
00403             // Cancel TimeOut timer
00404                         iTimer->Cancel(); 
00405                         iWriteStatus = EWaiting;
00406                         break;
00407                 // Request timed out
00408                 case ETimedOut:
00409                         iConsole->ErrorNotifyL(KWriteOperationTimedOut, KErrTimedOut);
00410                         break;
00411                 default:;
00412                         };
00413                 }
00414         else 
00415                 {
00416                 // Error: pass it up to user interface
00417                 _LIT(KCEchoWriteError,"\nCEchoWrite error");
00418                 iConsole->ErrorNotifyL(KCEchoWriteError, iStatus.Int());
00419                 }
00420         }
00421 /*
00422 Write data to a stream socket
00423 */
00424 void CEchoWrite::IssueWrite(const TChar &aChar)
00425         {
00426         // Set up buffer
00427         iBuffer.SetLength(0);
00428         iBuffer.Append(aChar);
00429         iEchoSocket->Write(iBuffer, iStatus);
00430         // Request timeout
00431         iTimer->After(iTimeOut);
00432         SetActive();
00433         iWriteStatus = ESending;
00434         };
00435 
00436 void CEchoWrite::IssueSendTo(TInetAddr &aAddr, const TChar &aChar)
00437 // This function is not actually used -
00438 // it shows how to write data to a datagram socket 
00439         {
00440         // Set up buffer
00441         iBuffer.SetLength(0);
00442         iBuffer.Append(aChar);
00443         iEchoSocket->SendTo(iBuffer,aAddr,NULL,iStatus);
00444         iTimer->After(iTimeOut);
00445         SetActive();
00446         iWriteStatus = ESending;
00447         };
00448 
00449 /*
00450  CTimeOutTimer: timer for comms time-outs
00451 */
00452 CTimeOutTimer::CTimeOutTimer(const TInt aPriority)
00453     : CTimer(aPriority)
00454     {
00455     }
00456 
00457 CTimeOutTimer::~CTimeOutTimer()
00458     {
00459         Cancel();
00460     }
00461 
00462 CTimeOutTimer* CTimeOutTimer::NewL(const TInt aPriority, MTimeOutNotify& aTimeOutNotify)
00463     {
00464     CTimeOutTimer *p = new (ELeave) CTimeOutTimer(aPriority);
00465     CleanupStack::PushL(p);
00466         p->ConstructL(aTimeOutNotify);
00467         CleanupStack::Pop();
00468     return p;
00469     }
00473 void CTimeOutTimer::ConstructL(MTimeOutNotify &aTimeOutNotify)
00474     {
00475         iNotify=&aTimeOutNotify;
00476         CTimer::ConstructL();
00477         CActiveScheduler::Add(this);
00478     }
00482 void CTimeOutTimer::RunL()
00483   
00484     {
00485         iNotify->TimerExpired();
00486         }
00487         

Generated by  doxygen 1.6.2