You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

92 regels
2.8 KiB

  1. using System;
  2. using System.Buffers;
  3. using MQTTnet.Adapter;
  4. using MQTTnet.Exceptions;
  5. using MQTTnet.Formatter;
  6. using MQTTnet.Packets;
  7. namespace MQTTnet.AspNetCore
  8. {
  9. public static class ReaderExtensions
  10. {
  11. public static bool TryDecode(this MqttPacketFormatterAdapter formatter, in ReadOnlySequence<byte> input, out MqttBasePacket packet, out SequencePosition consumed, out SequencePosition observed)
  12. {
  13. if (formatter == null) throw new ArgumentNullException(nameof(formatter));
  14. packet = null;
  15. consumed = input.Start;
  16. observed = input.End;
  17. var copy = input;
  18. if (copy.Length < 2)
  19. {
  20. return false;
  21. }
  22. var fixedheader = copy.First.Span[0];
  23. if (!TryReadBodyLength(ref copy, out var bodyLength))
  24. {
  25. return false;
  26. }
  27. if (copy.Length < bodyLength)
  28. {
  29. return false;
  30. }
  31. var bodySlice = copy.Slice(0, bodyLength);
  32. var buffer = bodySlice.GetArray();
  33. packet = formatter.Decode(new ReceivedMqttPacket(fixedheader, new MqttPacketBodyReader(buffer, 0, buffer.Length), buffer.Length + 2));
  34. consumed = bodySlice.End;
  35. observed = bodySlice.End;
  36. return true;
  37. }
  38. private static byte[] GetArray(this in ReadOnlySequence<byte> input)
  39. {
  40. if (input.IsSingleSegment)
  41. {
  42. return input.First.Span.ToArray();
  43. }
  44. // Should be rare
  45. return input.ToArray();
  46. }
  47. private static bool TryReadBodyLength(ref ReadOnlySequence<byte> input, out int result)
  48. {
  49. // Alorithm taken from https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html.
  50. var multiplier = 1;
  51. var value = 0;
  52. byte encodedByte;
  53. var index = 1;
  54. result = 0;
  55. var temp = input.Slice(0, Math.Min(5, input.Length)).GetArray();
  56. do
  57. {
  58. if (index == temp.Length)
  59. {
  60. return false;
  61. }
  62. encodedByte = temp[index];
  63. index++;
  64. value += (byte)(encodedByte & 127) * multiplier;
  65. if (multiplier > 128 * 128 * 128)
  66. {
  67. throw new MqttProtocolViolationException($"Remaining length is invalid (Data={string.Join(",", temp.AsSpan(1, index).ToArray())}).");
  68. }
  69. multiplier *= 128;
  70. } while ((encodedByte & 128) != 0);
  71. input = input.Slice(index);
  72. result = value;
  73. return true;
  74. }
  75. }
  76. }