Attribute.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. using STUN.Message.Attributes;
  2. using STUN.Message.Enums;
  3. using STUN.Utils;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. namespace STUN.Message
  8. {
  9. /// <summary>
  10. /// https://tools.ietf.org/html/rfc5389#section-15
  11. /// </summary>
  12. public class Attribute
  13. {
  14. /*
  15. Length 是大端
  16. 必须4字节对齐
  17. 对齐的字节可以是任意值
  18. 0 1 2 3
  19. 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
  20. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  21. | Type | Length |
  22. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  23. | Value (variable) ....
  24. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  25. */
  26. public AttributeType Type { get; set; } = AttributeType.Useless;
  27. public ushort Length { get; set; }
  28. public int RealLength => Type == AttributeType.Useless ? 0 : 4 + Length + (4 - Length % 4) % 4;
  29. public IAttribute Value { get; set; }
  30. private readonly byte[] _magicCookie;
  31. private readonly byte[] _transactionId;
  32. public Attribute() { }
  33. public Attribute(byte[] magicCookie, byte[] transactionId)
  34. {
  35. if (magicCookie.Length != 4 || transactionId.Length != 12)
  36. {
  37. throw new ArgumentException(@"Wrong Transaction ID length");
  38. }
  39. _magicCookie = magicCookie;
  40. _transactionId = transactionId;
  41. }
  42. public IEnumerable<byte> ToBytes()
  43. {
  44. var res = new List<byte>();
  45. res.AddRange(Convert.ToUInt16(Type).ToBe());
  46. res.AddRange(Length.ToBe());
  47. res.AddRange(Value.Bytes);
  48. var n = (4 - res.Count % 4) % 4; // 填充的字节数
  49. res.AddRange(BitUtils.GetRandomBytes(n));
  50. return res;
  51. }
  52. /// <returns>
  53. /// Parse 成功字节,0 则表示 Parse 失败
  54. /// </returns>
  55. public int TryParse(byte[] bytes)
  56. {
  57. if (bytes.Length < 4) return 0;
  58. Type = (AttributeType)BitUtils.FromBe(bytes[0], bytes[1]);
  59. Length = BitUtils.FromBe(bytes[2], bytes[3]);
  60. if (bytes.Length < 4 + Length) return 0;
  61. var value = bytes.Skip(4).Take(Length).ToArray();
  62. IAttribute t = Type switch
  63. {
  64. AttributeType.MappedAddress => new MappedAddressAttribute(),
  65. AttributeType.XorMappedAddress => new XorMappedAddressAttribute(_magicCookie, _transactionId),
  66. AttributeType.ResponseAddress => new ResponseAddressAttribute(),
  67. AttributeType.ChangeRequest => new ChangeRequestAttribute(),
  68. AttributeType.SourceAddress => new SourceAddressAttribute(),
  69. AttributeType.ChangedAddress => new ChangedAddressAttribute(),
  70. AttributeType.OtherAddress => new OtherAddressAttribute(),
  71. AttributeType.ReflectedFrom => new ReflectedFromAttribute(),
  72. AttributeType.ErrorCode => new ErrorCodeAttribute(),
  73. //TODO:more
  74. _ => new UselessAttribute()
  75. };
  76. Value = t.TryParse(value) ? t : null;
  77. return 4 + Length + (4 - Length % 4) % 4; // 对齐
  78. }
  79. }
  80. }