using System; using System.Collections.Generic; using System.Linq; using System.Net; namespace UdPunching { public class ExchangeMessage { // [0....] Flags // [1....] Section count // [2....] Section Type // [3...N] Section Content // [N+1..] Next Section Type public ExchangeMessageFlags Flags { get; set; } public DateTime? PeerTimeStamp { get; set; } public IPEndPoint PeerEndPoint { get; set; } public Guid? PeerId { get; set; } //TODO: more properties public ExchangeMessage() { } public ExchangeMessage(byte[] data) { var ptr = -1; Flags = (ExchangeMessageFlags)data[++ptr]; var count = data[++ptr]; for (var i = 0; i < count; i++) { var section = (ExchangeMessageSection)data[++ptr]; switch (section) { case ExchangeMessageSection.TimeStamp: ptr += data.ReadUnixTimeStamp(++ptr, out var timeStamp); PeerTimeStamp = timeStamp; break; case ExchangeMessageSection.PeerEndPoint: ptr += data.ReadIpEndPoint(++ptr, out var ipEndPoint); PeerEndPoint = ipEndPoint; break; case ExchangeMessageSection.PeerId: PeerId = new Guid(data.Skip(++ptr).Take(16).ToArray()); ptr += 16; break; default: //TODO: handle more sections throw new ArgumentOutOfRangeException(); } } } private Dictionary CreateSectionDictionary() { var dic = new Dictionary(); if (PeerTimeStamp.HasValue) { dic[ExchangeMessageSection.TimeStamp] = PeerTimeStamp.Value.ToUnixTimeStamp().ToLeBytes(); } if (null != PeerEndPoint) { var buf = new byte[17]; PeerEndPoint.Address.ToPaddingString().ToAsciiBytes(buf); PeerEndPoint.Port.ToLe16Bytes(buf, 15); dic[ExchangeMessageSection.PeerEndPoint] = buf; } if (PeerId.HasValue) { dic[ExchangeMessageSection.PeerId] = PeerId.Value.ToByteArray(); } //TODO: add more sections from properties return dic; } public byte[] ToBytes() { var dic = CreateSectionDictionary(); var lst = new List(1 + 1 + dic.Count + dic.Sum(p => p.Value.Length)) { (byte)Flags, (byte)dic.Count }; foreach (var kvp in dic) { lst.Add((byte)kvp.Key); lst.AddRange(kvp.Value); } return lst.ToArray(); } public void WriteToBuffer(byte[] buffer) { var dic = CreateSectionDictionary(); var ptr = -1; buffer[++ptr] = (byte)Flags; buffer[++ptr] = (byte)dic.Count; foreach (var item in dic) { buffer[++ptr] = (byte)item.Key; item.Value.CopyTo(buffer, ++ptr); } } } }