engine.cpp
上传用户:sempras
上传日期:2007-03-04
资源大小:821k
文件大小:15k
源码类别:

Symbian

开发平台:

C/C++

  1. ////////////////////////////////////////////////////////////////
  2. //
  3. //    engine.cpp
  4. //
  5. //    Copyright (C) 2001, Forum Nokia - The Developer Community
  6. //
  7. //
  8. ////////////////////////////////////////////////////////////////
  9. #include <e32base.h>
  10. #include "tcpudp.h"
  11. #include "engine.h"
  12. const TInt KTimeOut = 15000000; // 30 seconds time-out
  13. /**************************************************
  14. Class constructor
  15. **************************************************/
  16. CRunEngine::CRunEngine(): CActive(EPriorityHigh), iRecData(0,0), iSendData(0,0)   
  17. {
  18. }
  19. /*************************************************/
  20. /**************************************************
  21. Class destructor
  22. **************************************************/
  23. CRunEngine::~CRunEngine()
  24. {
  25. Cancel();
  26. iSocketServer.Close();
  27. if (iRecBuffer != 0)
  28. {
  29. delete iRecBuffer;
  30. iRecBuffer = 0;
  31. }
  32. if (iSendBuffer != 0)
  33. {
  34. delete iSendBuffer;
  35. iSendBuffer = 0;
  36. }
  37.     delete iMyTimer;
  38. }
  39. /**************************************************/
  40. /**************************************************
  41. Second phase constructor
  42. **************************************************/
  43. void CRunEngine::ConstructL(CTcpUdpView *aAppView)
  44. {
  45. iAppView    = aAppView;
  46. iSendBuffer = 0;
  47. iRecBuffer  = 0;
  48. iState = EIdle;
  49. CActiveScheduler::Add(this); //Adds itself to the scheduler
  50.     //Default values
  51. TPreferences preferences;
  52. DefaultPreferences(preferences);
  53.     iProtocol    = preferences.iProtocol;
  54. iRemotePort  = preferences.iRemotePort;
  55. iRemoteAddr.Copy(preferences.iRemoteAddr);
  56. iLocalPort   = preferences.iLocalPort;
  57. iLocalAddr.Copy(preferences.iLocalAddr);
  58. iCount       = preferences.iCount;
  59. iTrace       = preferences.iTrace;
  60. iPacketSize  = preferences.iPacketSize;
  61.     // Timer
  62.     iMyTimer = new(ELeave) CMyTimer;
  63. iMyTimer->ConstructL(this);
  64.     /*
  65. The client has to open a session with the ESOCK server by
  66. calling the Connect() method of the RSocketServ class. The
  67. connected socket server will be used later in the Start() 
  68. method for opening a socket.
  69. */
  70. // Connect() may leave
  71. CleanupStack::PushL(iMyTimer);
  72.     TInt err = iSocketServer.Connect();
  73.     if (err != KErrNone)
  74.     {
  75.         User::Panic(_L("Cannot open session with the ESOCK server!"), err);
  76.     }
  77. CleanupStack::Pop();
  78. }
  79. /*************************************************/
  80. /**************************************************
  81. Function: specifies default values
  82. **************************************************/
  83. void CRunEngine::DefaultPreferences(TPreferences &aPref)
  84. {
  85. //Default values
  86. aPref.iProtocol    = UDP;
  87. aPref.iRemotePort  = 7;
  88. aPref.iRemoteAddr  = _L("127.0.0.1");
  89. aPref.iLocalPort   = 2080;
  90. aPref.iLocalAddr   = _L("127.0.0.1");
  91. aPref.iCount       = 1000;
  92. aPref.iTrace       = EFalse ;
  93. aPref.iPacketSize  = 10 ;
  94. }
  95. /*************************************************/
  96. /**************************************************
  97. Function: passes current setting values
  98. **************************************************/
  99. void CRunEngine::GetPreferences(TPreferences &aPref)
  100. {
  101. aPref.iProtocol    = iProtocol;
  102. aPref.iRemotePort  = iRemotePort;
  103. aPref.iRemoteAddr.Copy(iRemoteAddr);
  104. aPref.iLocalPort   = iLocalPort;
  105. aPref.iLocalAddr.Copy(iLocalAddr) ;
  106. aPref.iCount       = iCount;
  107. aPref.iTrace       = iTrace;
  108. aPref.iPacketSize  = iPacketSize;
  109. }
  110. /*************************************************/
  111. /**************************************************
  112. Function: sets new setting values
  113. **************************************************/
  114. void CRunEngine::SetPreferences(TPreferences &aPref)
  115. {
  116. iProtocol         = aPref.iProtocol;
  117. iRemotePort       = aPref.iRemotePort;
  118. iRemoteAddr.Copy(aPref.iRemoteAddr) ;
  119. iLocalPort        = aPref.iLocalPort;
  120. iLocalAddr.Copy(aPref.iLocalAddr);
  121. iCount            = aPref.iCount;
  122. iTrace            = aPref.iTrace;
  123. iPacketSize       = aPref.iPacketSize;
  124. }
  125. /*************************************************/
  126. /**************************************************
  127. Function: starts the sending/receiving process
  128. **************************************************/
  129. TInt CRunEngine::Start()
  130. {
  131. TInt err = KErrNone;
  132. if (iPacketSize == 0)
  133. iPacketSize = 1;
  134. if (iSendBuffer != 0)
  135. delete iSendBuffer;
  136. // Create the sent packet with 1 extra byte for zero terminate
  137. iSendBuffer = HBufC8::NewL(iPacketSize+1);
  138. iSendData.Set(iSendBuffer->Des());
  139. // Initialize send data buffer
  140. iSendData.FillZ();
  141. iSendData.Zero();
  142. // dummy character in sending packet
  143. TChar xChar = 'X';
  144. // just fill the packet with dummy characters
  145. iSendData.Fill(xChar, iPacketSize-1);
  146. // Currently the Echoserver reads coming data till it receives a 
  147. // newline character. This is recognized as the end of each packet.
  148. TChar nl = 'n';
  149. iSendData.Append(nl);
  150. iSendData.ZeroTerminate();
  151. if (iRecBuffer != 0)
  152. delete iRecBuffer ;
  153. /* 
  154. Because the echoserver will send back the same data with the same 
  155. size, we create a received buffer with its length is equal to 
  156. the sent packet's size. Otherwise the size can be arbitrarily set.
  157. */
  158. // Allocate memory for the receiving buffer
  159. iRecBuffer = HBufC8::NewL(iPacketSize+1);
  160. TPtr8 auxPtr(( TUint8* )iRecBuffer->Des().Ptr(), iPacketSize);
  161. iRecData.Set(auxPtr);
  162. // reset other necessary parameters
  163. iState          = EIdle;
  164. iRecvPackets    = 0;
  165. iSentPackets    = 0;
  166. iTotalBytesRcvd = 0;
  167. /*
  168. Initialize the remote host parameters by setting its
  169. port and IP address
  170. */
  171. iSendAddr.SetPort(iRemotePort);     // remote port
  172. iSendAddr.Input(iRemoteAddr) ;      // remote address
  173. // set the local port
  174. iRecAddr.SetPort(iLocalPort);       // own port
  175. // make sure address family is correct
  176. if (iSendAddr.Family() == KAfInet)
  177. {
  178. // own address IPv4
  179. iRecAddr.Input(iLocalAddr) ;   
  180. iAppView->Write(_L("nUsing IPv4 addresses."));
  181. }
  182. // this sample application does not support IPv6 address
  183. else
  184. {
  185. iAppView->Write(_L("nNot support IP type."));
  186. return -1;
  187. }
  188. /*
  189. open a socket according to protocol type for sending/receiving data
  190. */
  191. if (iProtocol == TCP)
  192. err = iSocket.Open( iSocketServer,  // The socket server session 
  193. KAfInet,  // Constant for a protocol family 
  194. KSockStream,  // Stream socket
  195. KProtocolInetTcp // Constant which identifies the TCP protocol 
  196. );
  197. else
  198. err = iSocket.Open( iSocketServer,  // The socket server session
  199. KAfInet,  // Constant for a protocol family
  200. KSockDatagram,  // Datagram socket
  201. KProtocolInetUdp // Constant which identifies the UDP protocol
  202. );
  203. // checking Open()'s returned value
  204.     if (err != KErrNone)
  205.     {
  206.         iAppView->Write(_L("Cannot open the socket!.n"));
  207.         return err;
  208.     }
  209. /*
  210. setting the local port is equivalent to calling Bind() with 
  211. only the port set in the address.
  212. */
  213. err = iSocket.SetLocalPort(iLocalPort);
  214. if (err != KErrNone)
  215. {
  216. if (err == KErrInUse)
  217. iAppView->Write(_L("nLocal port is in use.n"));
  218. else
  219. iAppView->Write(_L("Socket binding failed.n"));
  220. return err;
  221. }
  222. /*
  223. For TCP sockets, an active connection is made to the remote 
  224. host. When the socket call completes successfully, the socket 
  225. is ready to send and receive data. To form a connection, 
  226. the protocol must establish a network interface and a route 
  227. to the destination. So the Connect() method is called.
  228. */
  229. if (iProtocol == TCP)
  230. {
  231. __ASSERT_ALWAYS(!IsActive(), User::Panic(_L("CRunEngine"), 1));
  232. // Connect
  233. iSocket.Connect(iSendAddr, iStatus);
  234. SetActive();
  235. TBuf<80> aux;
  236.         aux.Format(_L("nConnecting to port %d.n"), iRemotePort);
  237.     iAppView->Write(aux);
  238. iState = EConnected;
  239. }
  240. /*
  241. As UDP is a connectionless protocol, Connect() does not have to 
  242. be called before writing data with RSocket::SendTo(). However, 
  243. even for UDP Connect() can be also used to set the address for 
  244. all data sent from the socket, in which case Send()/Write() may 
  245. be used in addition to SendTo().
  246. In this example, SendTo() is employed so Connect() is not called
  247. */
  248. else // UDP
  249. {
  250. TBuf<80> aux;
  251.         aux.Format(_L("nSending UDP packets to port %d.n"), iRemotePort);
  252.     iAppView->Write(aux);
  253. SendPacket();
  254. iState = ESending;
  255. }
  256.     return KErrNone;
  257. }
  258. /*************************************************/
  259. /**************************************************
  260. Function: cancels any socket pending process
  261. **************************************************/
  262. void CRunEngine::Stop()
  263. {
  264. TBuf<80> aux;
  265. aux.Format(_L("Total number of sent packets: %d.n"), iSentPackets);
  266. iAppView->Write(aux);
  267. // Cancel() will cause a call to DoCancel() which
  268. // cancels any outstanding read/write operation.
  269. Cancel();  
  270. iStatus = KErrNone;
  271. iState = EClosing;
  272. RunL();
  273. if (iSendBuffer != 0)
  274. {
  275. delete iSendBuffer ;
  276.     iSendBuffer = 0 ;
  277. }
  278. if (iRecBuffer != 0)
  279. {
  280. delete iRecBuffer ;
  281. iRecBuffer = 0 ;
  282. }
  283. }
  284. /*************************************************/
  285. /**************************************************
  286. Function: handles the engine active object抯 
  287.   request completion event.
  288. **************************************************/
  289. void CRunEngine::RunL()
  290. {
  291. // holding information message to print on the screen
  292. TBuf<80> aux;
  293.     if (iStatus == KErrCancel || iStatus == KErrAbort)
  294.     { // This happens after calling cancel functions in socket
  295.         iStatus = KErrNone;
  296.     }
  297.     else if (iStatus != KErrNone)
  298.     {
  299.         iAppView->Write(_L("Something happened.n"));
  300.         aux.Format(_L("RunL received iStatus = %d.n"),iStatus);
  301.     iAppView->Write(aux);
  302.         CloseSockets();
  303.         iState = EIdle;
  304.         iAppView->UpdateBusyMsg();
  305.     }
  306. /*
  307.     The asynchronous operation that has completed and we 
  308. check the current state of communication action.
  309. iState was set to engage the engine to one of the
  310. following states:
  311. */
  312.     else switch (iState)
  313.     {
  314. // Idle status, nothing to send or receive
  315.         case EIdle:
  316.             break;
  317. // TCP connection is established
  318.         case EConnected:
  319. iAppView->Write(_L("Connected.n"));
  320. // Start sending the first packet
  321. SendPacket();
  322.             break;
  323. // a packet has been sent out
  324. case ESending:
  325. // increment the number of sent packets
  326. iSentPackets++ ;
  327. if (iTrace)
  328. {
  329. aux.Format(_L("Sent packet number %d.n"), iSentPackets);
  330. iAppView->Write(aux);
  331. }
  332. /*
  333. after a packet is sent, an echo packet is expected
  334. from the echoserver. ReceivePacket() will issue a 
  335. read/recv request and wait for a reply
  336. */
  337. ReceivePacket();
  338. // set the timer to timeout after 15 sec if the reply from
  339. // the echoserver does not come.
  340. if (iProtocol == UDP)
  341. if (!iMyTimer->IsActive())
  342. iMyTimer->After(KTimeOut);  // 15 sec
  343. // Prevent inactivity-related events from occuring (blank screen)
  344. User::ResetInactivityTime() ;
  345. break;
  346. // a reply (echoed) packet has come
  347.         case EReceiving:
  348. // if the reply comes while timeout is pending,
  349. // the timer must be cancelled
  350. if (iMyTimer->IsActive())
  351. iMyTimer->Cancel() ;
  352. // increment the number of received packets
  353. iRecvPackets++;
  354.             
  355. if (iTrace)
  356. {
  357. iTotalBytesRcvd += iRecData.Length();
  358. aux.Format(_L("Received %d bytes. Total %d.n"),iRecData.Length(), iTotalBytesRcvd);
  359. iAppView->Write(aux);
  360. }
  361. /*
  362. iCount is the number of packets to be sent set by a user, 
  363. if iCount is 0, the loop is infinity, otherwise, sending
  364. loop terminates when the number of echoed packets is equal
  365. to the value of iCount
  366. */
  367. if ( (iCount > 0) && (iRecvPackets >= iCount) )
  368. {
  369. Stop();
  370. break;
  371. }
  372. // call to send next packet
  373. SendPacket();
  374.             break;
  375. // when the Stop button is clicked or all echoed packets are received
  376.         case EClosing:
  377. // close the connected socket
  378.             CloseSockets();
  379.             iState = EIdle;
  380. iAppView->Write(_L("TcpUdp stopped.n"));
  381. iAppView->UpdateBusyMsg();
  382. break;
  383. // any undefined state
  384.         default:
  385.             iAppView->Write(_L("Something is wrong, State unknown.n"));
  386.             iState = EIdle;
  387.             break;
  388.     }
  389. }
  390. /*************************************************/
  391. /**************************************************
  392. Function: asynchronously reads/receives incoming 
  393. data from the socket.
  394. **************************************************/
  395. void CRunEngine::ReceivePacket()
  396. {
  397. iRecData.Zero();
  398. if (iProtocol == TCP)
  399. {
  400. iSocket.Recv(iRecData, 0, iStatus, iNumRcvd);
  401. }
  402. else // UDP
  403. iSocket.RecvFrom(iRecData, iRecAddr, 0, iStatus);
  404. iState = EReceiving;
  405.     SetActive();
  406. }
  407. /*************************************************/
  408. /**************************************************
  409. Function: handles the engine active object抯 
  410.   request completion event.
  411. **************************************************/
  412. void CRunEngine::SendPacket()
  413. {
  414. if (iProtocol == TCP)
  415.     iSocket.Send(iSendData, 0, iStatus, iNumRcvd);
  416. else // UDP
  417. iSocket.SendTo(iSendData, iSendAddr, 0, iStatus);
  418. // engage the engine to sending
  419. iState = ESending;
  420. SetActive();
  421. }
  422. /*************************************************/
  423. /**************************************************
  424. Function: releases the local port then 
  425. close the socket.
  426. **************************************************/
  427. void CRunEngine::CloseSockets()
  428. {
  429. // This ensures that TCP releases local port at once
  430. iSocket.CancelConnect();
  431.     iSocket.Close();
  432. }
  433. /*************************************************/
  434. /**************************************************
  435. Function: cancels outstanding operations then 
  436. close the socket.
  437. **************************************************/
  438. void CRunEngine::DoCancel()
  439. {
  440. if (iMyTimer->IsActive())
  441. iMyTimer->Cancel() ;
  442.     switch (iState)
  443.     {
  444.     case EIdle:
  445.     case EClosing:
  446. break;
  447. // cancel any asynchronous operations.
  448. case EConnected:
  449. iSocket.CancelAll();
  450.         break;
  451. // cancel an outstanding receive operation.
  452.     case EReceiving:
  453. iSocket.CancelRecv();
  454. break;
  455. // cancel an outstanding send operation
  456.     case ESending:
  457.         iSocket.CancelSend();
  458.         break;
  459.     default:
  460.         iAppView->Write(_L("Something is really wrong, State unknown.n"));
  461.         iSocket.CancelAll();
  462.         iState = EIdle;
  463.     }
  464. }
  465. //
  466. // class CMyTimer
  467. //
  468. CMyTimer::CMyTimer(): CTimer(0)
  469. {}
  470. void CMyTimer::ConstructL(CRunEngine *aEngine)
  471. {
  472. CTimer::ConstructL();
  473. CActiveScheduler::Add(this);
  474.     iEngine = aEngine;
  475. }
  476. void CMyTimer::RunL()
  477. {
  478. // if timer timeouts, call Stop() to cancel any 
  479. // outstanding operation and retry by calling Start()
  480. iEngine->Stop();
  481. iEngine->Start();
  482. }