Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

MqttPacketReader.cs 3.9 KiB

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