1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Net.Sockets;
  5. using System.Diagnostics;
  6. using System.Threading;
  7. using System.Net;
  8. using MessageLib;
  9. using NetworkLayer.Hashing;
  10. using Ionic.Zlib;
  11. using NetworkLayer;
  12.  
  13. namespace NetworkLayer.Client
  14. {
  15. public delegate void StringDelegate(object sender, string data);
  16. public delegate void MessageDelegate(object sender, Msg message);
  17.  
  18. public class ClientModule
  19. {
  20.  
  21. #region Events
  22.  
  23. public event MessageDelegate OnAckTimedOut;
  24. public event MessageDelegate OnDataReceived;
  25. public event StringDelegate OnErrorOccured;
  26. public event StringDelegate OnConnect;
  27. public event StringDelegate OnDisconnect;
  28. public event StringDelegate OnReconnect;
  29.  
  30. #endregion
  31.  
  32. #region Variables
  33.  
  34. // Back buffer.
  35. private byte[] backBuffer = new byte[StateObject.BufferSize * 10];
  36. private int backBufferCount = 0;
  37. private int bbmsgSize = 0;
  38.  
  39. public List<string> ackNeed = new List<string>();
  40. public List<Msg> backLog = new List<Msg>();
  41.  
  42. public static int AckTimeoutCount = 200;
  43.  
  44. public int ClientID = -1;
  45. public string ClientName = String.Empty;
  46. public string ClientType = String.Empty;
  47. public string ClientIP = String.Empty;
  48.  
  49. private int msgID = 0;
  50.  
  51. private bool _isCancel = false;
  52. public bool IsCancel
  53. {
  54. get { return _isCancel; }
  55. set { _isCancel = value; }
  56. }
  57.  
  58. private bool _isReady = false;
  59. public bool isReady
  60. {
  61. get { return isReady; }
  62. }
  63.  
  64. // Thread signal
  65. ManualResetEvent receiveDone = new ManualResetEvent(false);
  66. public ManualResetEvent clientDone = new ManualResetEvent(false);
  67. private Socket Client = new Socket(AddressFamily.InterNetwork,
  68. SocketType.Stream, ProtocolType.Tcp);
  69.  
  70. //Logging
  71. Logging.Logger logger = new Logging.Logger("clientModule.log", 5);
  72.  
  73. #endregion
  74.  
  75. #region Constructors
  76.  
  77. public ClientModule()
  78. {
  79. try
  80. {
  81. string strHostName = Dns.GetHostName();
  82. IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);
  83. IPAddress ipaddress = iphostentry.AddressList[0];
  84. this.ClientIP = ipaddress.ToString();
  85.  
  86. Client.SendBufferSize = 512;
  87. Client.ReceiveBufferSize = 512;
  88.  
  89. }
  90. catch (Exception ex)
  91. {
  92. logger.Error("ClientModule(), ");
  93. logger.Error("Error:\r\n" + ex.Message + "\r\nInnerException:\r\n" + ex.InnerException.Message);
  94. }
  95. }
  96.  
  97. #endregion
  98.  
  99. #region Connect Code
  100.  
  101. public void Connect(EndPoint remoteEP)
  102. {
  103. try
  104. {
  105. clientDone.Reset();
  106.  
  107. Client.BeginConnect(remoteEP,
  108. new AsyncCallback(ConnectCallback), Client);
  109.  
  110. clientDone.WaitOne();
  111.  
  112. }
  113. catch (Exception ex)
  114. {
  115. logger.Error("Connect(EndPoint), " + remoteEP.ToString());
  116. logger.Error("Error:\r\n" + ex.Message + "\r\nInnerException:\r\n" + ex.InnerException.Message);
  117. }
  118. }
  119.  
  120. private void ConnectCallback(IAsyncResult ar)
  121. {
  122. try
  123. {
  124. // Retrieve the socket from the state object.
  125. Socket client = (Socket)ar.AsyncState;
  126.  
  127. // Complete the connection.
  128. client.EndConnect(ar);
  129.  
  130. if (OnConnect != null)
  131. OnConnect(this, String.Format("Socket connected to {0}", client.RemoteEndPoint.ToString());
  132.  
  133. StateObject state = new StateObject();
  134. state.workSocket = client;
  135.  
  136. client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
  137. new AsyncCallback(ReceiveCallback), state);
  138.  
  139. clientDone.WaitOne();
  140.  
  141. }
  142. catch (Exception ex)
  143. {
  144. logger.Error("ConnectCallback, ");
  145. logger.Error("Error:\r\n" + ex.Message + "\r\nInnerException:\r\n" + ex.InnerException.Message);
  146. }
  147. }
  148.  
  149. #endregion
  150.  
  151. #region Receive Code
  152.  
  153. private void ReceiveCallback(IAsyncResult ar)
  154. {
  155. try
  156. {
  157. String content = String.Empty;
  158.  
  159. // Retrieve the state object and the handler socket
  160. // from the asynchronous state object.
  161. StateObject state = (StateObject)ar.AsyncState;
  162. Socket handler = state.workSocket;
  163.  
  164. // Read data from the client socket.
  165. int bytesRead = handler.EndReceive(ar);
  166. //bool gettingMore = false;
  167. if (bytesRead > 0)
  168. {
  169.  
  170. #region compressed Byte stream Management
  171.  
  172. string xmlMessage = String.Empty;
  173.  
  174. try
  175. {
  176. bbmsgSize = Int32.Parse(Encoding.ASCII.GetString(state.buffer, 0, 6));
  177. }
  178. catch
  179. {
  180. if (backBufferCount > 6)
  181. bbmsgSize = Int32.Parse(Encoding.ASCII.GetString(backBuffer, 0, 6));
  182. else
  183. {
  184. byte[] dummy = new byte[bytesRead + backBufferCount];
  185. Buffer.BlockCopy(backBuffer, 0, dummy, 0, backBufferCount);
  186. Buffer.BlockCopy(state.buffer, 0, dummy, backBufferCount, bytesRead);
  187. bbmsgSize = Int32.Parse(Encoding.ASCII.GetString(dummy, 0, 6));
  188. dummy = null;
  189. }
  190. }
  191.  
  192. if (bbmsgSize > (bytesRead + backBufferCount))
  193. {
  194. // Append data to the backBuffer
  195. Buffer.BlockCopy(state.buffer, 0, backBuffer, backBufferCount, bytesRead);
  196. backBufferCount += bytesRead;
  197. }
  198. else if (bbmsgSize == (bytesRead + backBufferCount))
  199. {
  200. // Append data to the backBuffer
  201. Buffer.BlockCopy(state.buffer, 0, backBuffer, backBufferCount, bytesRead);
  202. backBufferCount += bytesRead;
  203. // deflate the buffer data
  204. xmlMessage = deflateBytes(backBuffer);
  205. // Clean the backBuffer
  206. backBuffer = new byte[StateObject.BufferSize * 10];
  207. backBufferCount = 0;
  208. bbmsgSize = 0;
  209. }
  210. else if (bbmsgSize < (bytesRead + backBufferCount))
  211. {
  212. // Append data to the backBuffer
  213. Buffer.BlockCopy(state.buffer, 0, backBuffer, backBufferCount, bytesRead);
  214. backBufferCount += bytesRead;
  215. // do this untill all messages in backBuffer handled
  216. while (true)
  217. {
  218. int sMsgSize = 0;
  219. // make sure sure backBuffer is bigger than 6 bytes
  220. if (backBufferCount > 6)
  221. sMsgSize = Int32.Parse(Encoding.ASCII.GetString(backBuffer, 0, 6));
  222. else
  223. break;
  224. // make sure backBuffer is bigger than the msg that it wants to retrieve
  225. if (backBufferCount < sMsgSize)
  226. {
  227. bbmsgSize = sMsgSize;
  228. break;
  229. }
  230. // Copy out the msg from the backBuffer
  231. byte[] wBuffer = new byte[sMsgSize];
  232. Buffer.BlockCopy(backBuffer, 0, wBuffer, 0, sMsgSize);
  233. // deflate the buffer data
  234. string xml = deflateBytes(wBuffer);
  235. //sb.Append(xml);
  236. //sb.Append("<delem>");
  237. xmlMessage += xml.Trim() + "<delem>";
  238. xml = null;
  239. // remove the message from the backBuffer
  240. // make sure its not the end of the buffer
  241. backBufferCount = backBufferCount - sMsgSize;
  242. if (backBufferCount == 0)
  243. {
  244. bbmsgSize = 0;
  245. backBuffer = new byte[StateObject.BufferSize * 10];
  246. break;
  247. }
  248. // Copy the remaining backBuffer to the rBuffer (remaindingBuffer)
  249. // Then clear the backBuffer and put the remainding buffer back into
  250. // the backBuffer for future use.
  251. byte[] rBuffer = new byte[backBufferCount];
  252. Buffer.BlockCopy(backBuffer, sMsgSize, rBuffer, 0, rBuffer.Length);
  253. backBuffer = new byte[StateObject.BufferSize * 10];
  254. Buffer.BlockCopy(rBuffer, 0, backBuffer, 0, backBufferCount);
  255. }
  256. }
  257. // clear the reading buffer so that you can use it again
  258. state.buffer = new byte[StateObject.BufferSize];
  259.  
  260. #endregion
  261.  
  262. if (xmlMessage != String.Empty)
  263. {
  264. string[] msgParts = xmlMessage.Split(new string[] { "<delem>" }, StringSplitOptions.RemoveEmptyEntries);
  265. for (int i = 0; i < msgParts.Length; i++)
  266. {
  267. Msg reader = new Msg();
  268. Msg msg = reader.DeSerialize(msgParts[i]);
  269. MessageHandler(msg);
  270. }
  271.  
  272. }
  273.  
  274. content = string.Empty;
  275. receiveDone.Set();
  276. }
  277. if (handler != null && handler.Connected == true)
  278. {
  279. handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
  280. new AsyncCallback(ReceiveCallback), state);
  281. receiveDone.WaitOne();
  282. }
  283. }
  284. catch (Exception ex)
  285. {
  286. logger.Error("ReceiveCallback, ");
  287. logger.Error("Error:\r\n" + ex.Message + "\r\nInnerException:\r\n" + ex.InnerException.Message);
  288. }
  289. }
  290.  
  291. private string deflateBytes(byte[] wBuffer)
  292. {
  293. string xmlMessage = String.Empty;
  294.  
  295. try
  296. {
  297. int msgSize = Int32.Parse(Encoding.ASCII.GetString(wBuffer, 0, 6));
  298. int crcSize = Int32.Parse(Encoding.ASCII.GetString(wBuffer, 6, 2));
  299.  
  300. byte[] crcByte = new byte[crcSize];
  301. Buffer.BlockCopy(wBuffer, 8, crcByte, 0, crcSize);
  302. byte[] workBuffer = new byte[msgSize - (8 + crcSize)];
  303. Buffer.BlockCopy(wBuffer, 8 + crcSize, workBuffer, 0, msgSize - (8 + crcSize));
  304.  
  305. Crc32 crc = new Crc32();
  306. byte[] checkSum = crc.ComputeHash(workBuffer);
  307.  
  308. ZlibCodec compressor = new ZlibCodec(CompressionMode.Decompress);
  309. //int rc = compressor.InitializeDeflate(CompressionLevel.Level9);
  310.  
  311. byte[] deflatedBuffer = new byte[51200];
  312.  
  313. compressor.InputBuffer = workBuffer;
  314. compressor.NextIn = 0;
  315.  
  316. compressor.OutputBuffer = deflatedBuffer;
  317. compressor.NextOut = 0;
  318.  
  319. compressor.AvailableBytesOut = deflatedBuffer.Length;
  320. compressor.AvailableBytesIn = workBuffer.Length;
  321. int rc1 = compressor.Inflate(FlushType.None);
  322. int rc2 = compressor.Inflate(FlushType.Finish);
  323. int rc3 = compressor.EndInflate();
  324.  
  325. xmlMessage = Encoding.ASCII.GetString(deflatedBuffer);
  326.  
  327. xmlMessage = (xmlMessage.Split(new string[] { "</Msg>" }, StringSplitOptions.RemoveEmptyEntries)[0] + "</Msg>");
  328.  
  329. }
  330. catch (Exception ex)
  331. {
  332. logger.Error("deflateBytes, wBuffer:" + Encoding.ASCII.GetString(wBuffer));
  333. logger.Error("Error:\r\n" + ex.Message + "\r\nInnerException:\r\n" + ex.InnerException.Message);
  334. }
  335. return xmlMessage;
  336. }
  337.  
  338. public void MessageHandler(Msg msg)
  339. {
  340. try
  341. {
  342. if (msg.Header != null)
  343. {
  344. switch (msg.Header.msgType)
  345. {
  346. case "handShake":
  347. handShake handshake = (handShake)msg.Body.Messages[0];
  348. handshake.ClientName = this.ClientName;
  349. handshake.ClientType = this.ClientType;
  350. handshake.ClientIP = this.ClientIP;
  351. this.ClientID = handshake.ClientID;
  352.  
  353. Header head = new Header();
  354. head.fromSystem = this.ClientIP;
  355. head.msgType = "handShake";
  356. head.toSystem = msg.Header.fromSystem;
  357. head.msgID = (msgID++).ToString();
  358.  
  359. Body body = new Body();
  360. body.Add(handshake);
  361.  
  362. Msg sendMessage = new Msg(head, body);
  363.  
  364. _isReady = true;
  365. Send(sendMessage);
  366.  
  367. break;
  368. default:
  369. OnDataReceived(this, msg);
  370.  
  371. break;
  372. }
  373. // Signal that the connection has been made.
  374. clientDone.Set();
  375. }
  376. else if (msg.ACK != null)
  377. {
  378. switch (msg.ACK.msgType)
  379. {
  380. case "handShake":
  381. OnDataReceived(this, msg);
  382.  
  383. break;
  384. default:
  385. OnDataReceived(this, msg);
  386.  
  387. break;
  388. }
  389. int index = 0;
  390. foreach (string id in ackNeed)
  391. {
  392. if (id == msg.ACK.msgID)
  393. {
  394. backLog.RemoveAt(index);
  395. ackNeed.Remove(id);
  396. break;
  397. }
  398. index++;
  399. }
  400. clientDone.Set();
  401. }
  402.  
  403. }
  404. catch (Exception ex)
  405. {
  406. logger.Error("MessageHandler, ");
  407. logger.Error("Error:\r\n" + ex.Message + "\r\nInnerException:\r\n" + ex.InnerException.Message);
  408. }
  409. }
  410.  
  411. #endregion
  412.  
  413. #region Send Code
  414.  
  415. public void Send(Msg message)
  416. {
  417. try
  418. {
  419. if (_isReady)
  420. {
  421. clientDone.Reset();
  422. //Thread.Sleep(100);
  423. if (message.Header.msgID == null)
  424. message.Header.msgID = (this.msgID++).ToString();
  425.  
  426.  
  427. lock (ackNeed)
  428. {
  429. ackNeed.Add(message.Header.msgID);
  430. backLog.Add(message);
  431. }
  432.  
  433. string xmlMessage = message.Serialize();// + Convert.ToChar(3);
  434.  
  435. #region Converting to byte[] compressing, hashing data and setting up Header
  436.  
  437. // Convert the string data to byte data using ASCII encoding.
  438. // And compress the Bytes
  439.  
  440. byte[] byteData = Encoding.ASCII.GetBytes(xmlMessage);
  441. byte[] decompByteData = new byte[xmlMessage.Length];
  442. byte[] compressedByteData = new byte[xmlMessage.Length];
  443.  
  444. ZlibCodec compressor = new ZlibCodec();
  445. int rc = compressor.InitializeDeflate(CompressionLevel.Level9);
  446.  
  447. compressor.InputBuffer = Encoding.ASCII.GetBytes(xmlMessage);
  448. compressor.NextIn = 0;
  449.  
  450. compressor.OutputBuffer = compressedByteData;
  451. compressor.NextOut = 0;
  452.  
  453. compressor.AvailableBytesOut = xmlMessage.Length;
  454. compressor.AvailableBytesIn = xmlMessage.Length;
  455. int rc1 = compressor.Deflate(FlushType.None);
  456. int rc2 = compressor.Deflate(FlushType.Finish);
  457. int rc3 = compressor.EndDeflate();
  458.  
  459. byte[] finalByteData = new byte[((int)compressor.TotalBytesOut)];
  460. Buffer.BlockCopy(compressedByteData, 0, finalByteData, 0, (int)compressor.TotalBytesOut);
  461.  
  462. Crc32 crc = new Crc32();
  463. byte[] computedHash = crc.ComputeHash(finalByteData);
  464. byte[] header = new byte[8 + computedHash.Length];
  465.  
  466. int headLen = header.Length;
  467. int bodyLen = (int)compressor.TotalBytesOut;
  468. int totalLen = headLen + bodyLen;
  469.  
  470. byte[] lencomputedHash = new byte[2];
  471. lencomputedHash = Encoding.ASCII.GetBytes(computedHash.Length.ToString());
  472.  
  473. byte[] lenBytes = new byte[6];
  474. lenBytes = Encoding.ASCII.GetBytes(totalLen.ToString());
  475.  
  476. Buffer.BlockCopy(lenBytes, 0, header, 0, lenBytes.Length);
  477. Buffer.BlockCopy(lencomputedHash, 0, header, 6, lencomputedHash.Length);
  478. Buffer.BlockCopy(computedHash, 0, header, 8, computedHash.Length);
  479.  
  480. byte[] hashedFinal = new byte[((int)compressor.TotalBytesOut) + header.Length];
  481. Buffer.BlockCopy(header, 0, hashedFinal, 0, header.Length);
  482. Buffer.BlockCopy(finalByteData, 0, hashedFinal, header.Length, finalByteData.Length);
  483.  
  484. // Testing multi messages
  485.  
  486. //byte[] dummy3 = new byte[hashedFinal.Length * 3];
  487. //for (int i = 0; i < 3; i++)
  488. //{
  489. // Buffer.BlockCopy(hashedFinal, 0, dummy3, i * hashedFinal.Length, hashedFinal.Length);
  490. //}
  491.  
  492. #endregion
  493.  
  494. // Begin sending the data to the remote device.
  495. Client.BeginSend(hashedFinal, 0, hashedFinal.Length, 0,
  496. new AsyncCallback(SendCallback), Client);
  497.  
  498. clientDone.WaitOne();
  499.  
  500. AckTimeOutObject ackTO = new AckTimeOutObject();
  501. ackTO.timeout = AckTimeoutCount;
  502. ackTO.msgID = message.Header.msgID;
  503.  
  504. Thread ackThread = new Thread(AckTimeout);
  505. ackThread.IsBackground = true;
  506. ackThread.Start(ackTO);
  507. }
  508.  
  509. }
  510. catch (Exception ex)
  511. {
  512. logger.Error("Send, Message:\r\n" + message.Serialize());
  513. logger.Error("Error:\r\n" + ex.Message + "\r\nInnerException:\r\n" + ex.InnerException.Message);
  514.  
  515. }
  516. }
  517.  
  518. public void SendACK(string msgType, string msgAction, string msgID, string toSystem, string msgProcessedBy)
  519. {
  520. try
  521. {
  522. ACK ack = new ACK();
  523. ack.fromSystem = this.ClientIP;
  524. ack.toSystem = toSystem;
  525. ack.msgType = msgType;
  526. ack.msgID = msgID;
  527. ack.msgAction = msgAction;
  528. ack.msgProcessedBy = msgProcessedBy;
  529. Msg message = new Msg(ack);
  530. Send(message);
  531.  
  532. }
  533. catch (Exception ex)
  534. {
  535. logger.Error("SendACK, ");
  536. logger.Error("Error:\r\n" + ex.Message + "\r\nInnerException:\r\n" + ex.InnerException.Message);
  537. }
  538. }
  539.  
  540. public void AckTimeout(object acktimeout)
  541. {
  542. AckTimeOutObject ackTO = (AckTimeOutObject)acktimeout;
  543. Thread.Sleep(ackTO.timeout);
  544. bool found = false;
  545. int index = 0;
  546.  
  547. try
  548. {
  549. lock (ackNeed)
  550. {
  551. foreach (string id in ackNeed)
  552. {
  553. if (id == ackTO.msgID)
  554. {
  555. found = true;
  556. ackNeed.Remove(id);
  557. break;
  558. }
  559. index++;
  560. }
  561. if (found)
  562. {
  563. if (OnAckTimedOut != null)
  564. {
  565. OnAckTimedOut(this, backLog[index]);
  566. backLog.RemoveAt(index);
  567. }
  568. }
  569. }
  570. }
  571. catch (Exception ex)
  572. {
  573. string exMsg = ex.Message;
  574. if (exMsg.Contains("Collection was modified;"))
  575. {
  576. ackTO.timeout = 10;
  577. Thread ackThread = new Thread(AckTimeout);
  578. ackThread.IsBackground = true;
  579. ackThread.Start(ackTO);
  580. }
  581. }
  582. }
  583.  
  584. public void SendCallback(IAsyncResult ar)
  585. {
  586. try
  587. {
  588. // Retrieve the socket from the state object.
  589. Socket handler = (Socket)ar.AsyncState;
  590.  
  591. // Complete sending the data to the remote device.
  592. int bytesSent = handler.EndSend(ar);
  593. //Console.WriteLine("Sent {0} bytes to server.", bytesSent);
  594.  
  595. clientDone.Set();
  596.  
  597. }
  598. catch (Exception ex)
  599. {
  600. logger.Error("SendCallback, ");
  601. logger.Error("Error:\r\n" + ex.Message + "\r\nInnerException:\r\n" + ex.InnerException.Message);
  602. }
  603. }
  604.  
  605. #endregion
  606.  
  607. #region Keep Alive
  608.  
  609. private void startKeepAlive()
  610. {
  611. Client.Poll(100, SelectMode.SelectError);
  612. }
  613.  
  614. #endregion
  615.  
  616. public void Shutdown()
  617. {
  618. try
  619. {
  620. Client.Shutdown(SocketShutdown.Both);
  621. Client.Close();
  622.  
  623. }
  624. catch (Exception ex)
  625. {
  626. logger.Error("Shutdown(), ");
  627. logger.Error("Error:\r\n" + ex.Message + "\r\nInnerException:\r\n" + ex.InnerException.Message);
  628. }
  629. }
  630.  
  631. }
  632. }
  633.