ExchangeMessage.cs 4.1 KB

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