ExchangeMessage.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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 ExchangeMessageFlags Flags { get; set; }
  15. public DateTime? PeerTimeStamp { get; set; }
  16. public IPEndPoint PeerEndPoint { get; set; }
  17. public Guid? PeerId { get; set; }
  18. //TODO: more properties
  19. public ExchangeMessage()
  20. {
  21. }
  22. public ExchangeMessage(byte[] data)
  23. {
  24. var ptr = -1;
  25. Flags = (ExchangeMessageFlags)data[++ptr];
  26. var count = data[++ptr];
  27. for (var i = 0; i < count; i++)
  28. {
  29. var section = (ExchangeMessageSection)data[++ptr];
  30. switch (section)
  31. {
  32. case ExchangeMessageSection.TimeStamp:
  33. ptr += data.ReadUnixTimeStamp(++ptr, out var timeStamp);
  34. PeerTimeStamp = timeStamp;
  35. break;
  36. case ExchangeMessageSection.PeerEndPoint:
  37. ptr += data.ReadIpEndPoint(++ptr, out var ipEndPoint);
  38. PeerEndPoint = ipEndPoint;
  39. break;
  40. case ExchangeMessageSection.PeerId:
  41. PeerId = new Guid(data.Skip(++ptr).Take(16).ToArray());
  42. ptr += 16;
  43. break;
  44. default:
  45. //TODO: handle more sections
  46. throw new ArgumentOutOfRangeException();
  47. }
  48. }
  49. }
  50. private Dictionary<ExchangeMessageSection, byte[]> CreateSectionDictionary()
  51. {
  52. var dic = new Dictionary<ExchangeMessageSection, byte[]>();
  53. if (PeerTimeStamp.HasValue)
  54. {
  55. dic[ExchangeMessageSection.TimeStamp] = PeerTimeStamp.Value.ToUnixTimeStamp().ToLeBytes();
  56. }
  57. if (null != PeerEndPoint)
  58. {
  59. var buf = new byte[17];
  60. PeerEndPoint.Address.ToPaddingString().ToAsciiBytes(buf);
  61. PeerEndPoint.Port.ToLe16Bytes(buf, 15);
  62. dic[ExchangeMessageSection.PeerEndPoint] = buf;
  63. }
  64. if (PeerId.HasValue)
  65. {
  66. dic[ExchangeMessageSection.PeerId] = PeerId.Value.ToByteArray();
  67. }
  68. //TODO: add more sections from properties
  69. return dic;
  70. }
  71. public byte[] ToBytes()
  72. {
  73. var dic = CreateSectionDictionary();
  74. var lst = new List<byte>(1 + 1 + dic.Count + dic.Sum(p => p.Value.Length))
  75. {
  76. (byte)Flags,
  77. (byte)dic.Count
  78. };
  79. foreach (var kvp in dic)
  80. {
  81. lst.Add((byte)kvp.Key);
  82. lst.AddRange(kvp.Value);
  83. }
  84. return lst.ToArray();
  85. }
  86. public void WriteToBuffer(byte[] buffer)
  87. {
  88. var dic = CreateSectionDictionary();
  89. var ptr = -1;
  90. buffer[++ptr] = (byte)Flags;
  91. buffer[++ptr] = (byte)dic.Count;
  92. foreach (var item in dic)
  93. {
  94. buffer[++ptr] = (byte)item.Key;
  95. item.Value.CopyTo(buffer, ++ptr);
  96. }
  97. }
  98. }
  99. }