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.
 
 
 
 

110 lines
3.4 KiB

  1. using System;
  2. using System.IO;
  3. using System.Text;
  4. using System.Threading;
  5. using System.Threading.Tasks;
  6. using MQTTnet.Channel;
  7. using MQTTnet.Exceptions;
  8. using MQTTnet.Internal;
  9. namespace MQTTnet.Serializer
  10. {
  11. public static class MqttPacketReader
  12. {
  13. public static async Task<byte> ReadFixedHeaderAsync(IMqttChannel channel, CancellationToken cancellationToken)
  14. {
  15. // Wait for the next package which starts with the header. At this point there will probably
  16. // some large delay and thus the thread should be put back to the pool (await). So ReadByte()
  17. // is not an option here.
  18. var buffer = new byte[1];
  19. var readCount = await channel.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
  20. if (readCount <= 0)
  21. {
  22. ExceptionHelper.ThrowGracefulSocketClose();
  23. }
  24. return buffer[0];
  25. }
  26. public static ushort ReadUInt16(this Stream stream)
  27. {
  28. var buffer = stream.ReadBytes(2);
  29. var temp = buffer[0];
  30. buffer[0] = buffer[1];
  31. buffer[1] = temp;
  32. return BitConverter.ToUInt16(buffer, 0);
  33. }
  34. public static string ReadStringWithLengthPrefix(this Stream stream)
  35. {
  36. var buffer = stream.ReadWithLengthPrefix();
  37. if (buffer.Length == 0)
  38. {
  39. return string.Empty;
  40. }
  41. return Encoding.UTF8.GetString(buffer, 0, buffer.Length);
  42. }
  43. public static byte[] ReadWithLengthPrefix(this Stream stream)
  44. {
  45. var length = stream.ReadUInt16();
  46. if (length == 0)
  47. {
  48. return new byte[0];
  49. }
  50. return stream.ReadBytes(length);
  51. }
  52. public static byte[] ReadRemainingData(this Stream stream)
  53. {
  54. return stream.ReadBytes((int)(stream.Length - stream.Position));
  55. }
  56. public static async Task<int> ReadBodyLengthAsync(IMqttChannel channel, CancellationToken cancellationToken)
  57. {
  58. // Alorithm taken from https://docs.oasis-open.org/mqtt/mqtt/v3.1.1/errata01/os/mqtt-v3.1.1-errata01-os-complete.html.
  59. var multiplier = 1;
  60. var value = 0;
  61. int encodedByte;
  62. var buffer = new byte[1];
  63. do
  64. {
  65. if (cancellationToken.IsCancellationRequested)
  66. {
  67. throw new TaskCanceledException();
  68. }
  69. var readCount = await channel.ReadAsync(buffer, 0, 1, cancellationToken).ConfigureAwait(false);
  70. if (readCount <= 0)
  71. {
  72. ExceptionHelper.ThrowGracefulSocketClose();
  73. }
  74. encodedByte = buffer[0];
  75. value += (byte)(encodedByte & 127) * multiplier;
  76. if (multiplier > 128 * 128 * 128)
  77. {
  78. throw new MqttProtocolViolationException("Remaining length is invalid.");
  79. }
  80. multiplier *= 128;
  81. } while ((encodedByte & 128) != 0);
  82. return value;
  83. }
  84. private static byte[] ReadBytes(this Stream stream, int count)
  85. {
  86. var buffer = new byte[count];
  87. stream.Read(buffer, 0, count);
  88. return buffer;
  89. }
  90. }
  91. }