ExchangeMessage.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Net;
  5. namespace UdPunching
  6. {
  7. public class ExchangeMessage
  8. {
  9. // [0.....] Id
  10. // [1.....] Section count
  11. // [2.....] Section Type
  12. // [3....N] Section Content
  13. // [N....M] Next Section Type
  14. public ExchangeMessageId Id { get; set; }
  15. public DateTime? TimeStamp { get; set; }
  16. public IPEndPoint PeerEndPoint { get; set; }
  17. public Guid? PeerId { get; set; }
  18. public byte[] PayloadBytes { get; set; }
  19. //TODO: more properties
  20. public ExchangeMessage()
  21. {
  22. }
  23. public ExchangeMessage(ExchangeMessageId id)
  24. {
  25. Id = id;
  26. TimeStamp = DateTime.Now;
  27. }
  28. public ExchangeMessage(byte[] data)
  29. {
  30. var ptr = -1;
  31. Id = (ExchangeMessageId)data[++ptr];
  32. var count = data[++ptr];
  33. for (var i = 0; i < count; i++)
  34. {
  35. var section = (ExchangeMessageSection)data[++ptr];
  36. switch (section)
  37. {
  38. case ExchangeMessageSection.TimeStamp:
  39. ptr += data.ReadUnixTimeStamp(++ptr, out var timeStamp);
  40. TimeStamp = timeStamp;
  41. break;
  42. case ExchangeMessageSection.PeerEndPoint:
  43. ptr += data.ReadIpEndPoint(++ptr, out var ipEndPoint);
  44. PeerEndPoint = ipEndPoint;
  45. break;
  46. case ExchangeMessageSection.PeerId:
  47. PeerId = new Guid(data.Skip(++ptr).Take(16).ToArray());
  48. ptr += 16;
  49. break;
  50. case ExchangeMessageSection.PayloadData:
  51. ptr += data.ReadLeInt16(out var len, ++ptr);
  52. var payload = new byte[len];
  53. Buffer.BlockCopy(data, ++ptr, payload, 0, len);
  54. ptr += len;
  55. PayloadBytes = payload;
  56. break;
  57. default:
  58. //TODO: handle more sections
  59. throw new ArgumentOutOfRangeException();
  60. }
  61. }
  62. }
  63. private Dictionary<ExchangeMessageSection, byte[]> CreateSectionDictionary()
  64. {
  65. var dic = new Dictionary<ExchangeMessageSection, byte[]>();
  66. if (TimeStamp.HasValue)
  67. {
  68. dic[ExchangeMessageSection.TimeStamp] = TimeStamp.Value.ToUnixTimeStamp().ToLeInt32Bytes();
  69. }
  70. if (null != PeerEndPoint)
  71. {
  72. var buf = new byte[17];
  73. PeerEndPoint.Address.ToPaddingString().WriteAsciiBytesTo(buf);
  74. PeerEndPoint.Port.WriteLeInt16To(buf, 15);
  75. dic[ExchangeMessageSection.PeerEndPoint] = buf;
  76. }
  77. if (PeerId.HasValue)
  78. {
  79. dic[ExchangeMessageSection.PeerId] = PeerId.Value.ToByteArray();
  80. }
  81. if (null != PayloadBytes)
  82. {
  83. var buf = new byte[PayloadBytes.Length + 2];
  84. PayloadBytes.Length.WriteLeInt16To(buf);
  85. PayloadBytes.CopyTo(buf, 2);
  86. dic[ExchangeMessageSection.PayloadData] = buf;
  87. }
  88. //TODO: add more sections from properties
  89. return dic;
  90. }
  91. public byte[] ToBytes()
  92. {
  93. var dic = CreateSectionDictionary();
  94. var lst = new List<byte>(1 + 1 + dic.Count + dic.Sum(p => p.Value.Length))
  95. {
  96. (byte)Id,
  97. (byte)dic.Count
  98. };
  99. foreach (var kvp in dic)
  100. {
  101. lst.Add((byte)kvp.Key);
  102. lst.AddRange(kvp.Value);
  103. }
  104. return lst.ToArray();
  105. }
  106. public void WriteToBuffer(byte[] buffer)
  107. {
  108. var dic = CreateSectionDictionary();
  109. var ptr = -1;
  110. buffer[++ptr] = (byte)Id;
  111. buffer[++ptr] = (byte)dic.Count;
  112. foreach (var item in dic)
  113. {
  114. buffer[++ptr] = (byte)item.Key;
  115. item.Value.CopyTo(buffer, ++ptr);
  116. }
  117. }
  118. }
  119. }