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.
 
 
 
 

86 lines
2.5 KiB

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