1592 bug of mqttbufferreader (#1593)

This commit is contained in:
Christian
2022-11-29 20:23:20 +01:00
committed by GitHub
parent 11e64ef018
commit 56750adfe4
13 changed files with 283 additions and 69 deletions
+59 -33
View File
@@ -13,15 +13,14 @@ namespace MQTTnet.Formatter
public sealed class MqttBufferReader
{
byte[] _buffer = EmptyBuffer.Array;
int _initialPosition;
int _length;
int _position;
int _maxPosition;
int _offset;
public bool EndOfStream => _position == _length;
public int Position => _position;
public int BytesLeft => _length - _position;
public int BytesLeft => _maxPosition - Position;
public bool EndOfStream => BytesLeft == 0;
public int Position { get; private set; }
public byte[] ReadBinaryData()
{
@@ -35,8 +34,8 @@ namespace MQTTnet.Formatter
ValidateReceiveBuffer(length);
var result = new byte[length];
Array.Copy(_buffer, _position, result, 0, length);
_position += length;
Array.Copy(_buffer, Position + _offset, result, 0, length);
Position += length;
return result;
}
@@ -45,32 +44,42 @@ namespace MQTTnet.Formatter
{
ValidateReceiveBuffer(1);
return _buffer[_position++];
return _buffer[Position++];
}
public uint ReadFourByteInteger()
{
ValidateReceiveBuffer(4);
var byte0 = _buffer[_position++];
var byte1 = _buffer[_position++];
var byte2 = _buffer[_position++];
var byte3 = _buffer[_position++];
#if NETCOREAPP3_0_OR_GREATER
var value = System.Runtime.InteropServices.MemoryMarshal.Read<uint>(_buffer.AsSpan().Slice(Position));
value = System.Buffers.Binary.BinaryPrimitives.ReverseEndianness(value);
#else
var byte0 = _buffer[_offset + Position];
var byte1 = _buffer[_offset + Position + 1];
var byte2 = _buffer[_offset + Position + 2];
var byte3 = _buffer[_offset + Position + 3];
return (uint)((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
var value = (uint)((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
#endif
Position += 4;
return value;
}
public byte[] ReadRemainingData()
{
var bufferLength = _length - _position;
var bufferLength = _maxPosition - Position - _offset;
if (bufferLength == 0)
{
return EmptyBuffer.Array;
}
var buffer = new byte[bufferLength];
Array.Copy(_buffer, _position, buffer, 0, bufferLength);
Array.Copy(_buffer, Position + _offset, buffer, 0, bufferLength);
Position += bufferLength;
return buffer;
}
@@ -83,11 +92,17 @@ namespace MQTTnet.Formatter
{
return string.Empty;
}
ValidateReceiveBuffer(length);
var result = Encoding.UTF8.GetString(_buffer, _position, length);
_position += length;
#if NETCOREAPP3_0_OR_GREATER
// AsSpan() version is slightly faster. Not much but at least a little bit.
var result = Encoding.UTF8.GetString(_buffer.AsSpan(_offset + Position, length));
#else
var result = Encoding.UTF8.GetString(_buffer, _offset + Position, length);
#endif
Position += length;
return result;
}
@@ -95,10 +110,18 @@ namespace MQTTnet.Formatter
{
ValidateReceiveBuffer(2);
var msb = _buffer[_position++];
var lsb = _buffer[_position++];
#if NETCOREAPP3_0_OR_GREATER
var value = System.Runtime.InteropServices.MemoryMarshal.Read<ushort>(_buffer.AsSpan().Slice(Position));
value = System.Buffers.Binary.BinaryPrimitives.ReverseEndianness(value);
#else
var msb = _buffer[_offset + Position];
var lsb = _buffer[_offset + Position + 1];
return (ushort)((msb << 8) | lsb);
var value = (ushort)((msb << 8) | lsb);
#endif
Position += 2;
return value;
}
public uint ReadVariableByteInteger()
@@ -125,23 +148,26 @@ namespace MQTTnet.Formatter
public void Seek(int position)
{
_position = _initialPosition + position;
Position = position;
}
public void SetBuffer(byte[] buffer, int position, int length)
public void SetBuffer(byte[] buffer, int offset, int length)
{
_buffer = buffer;
_initialPosition = position;
_position = position;
_length = length;
_buffer = buffer ?? throw new ArgumentNullException(nameof(buffer));
_offset = offset;
Position = 0;
_maxPosition = length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void ValidateReceiveBuffer(int length)
{
if (_length < _position + length)
var newPosition = Position + _offset + length;
if (_maxPosition < newPosition)
{
throw new MqttProtocolViolationException($"Expected at least {Position + length} bytes but there are only {_length} bytes");
throw new MqttProtocolViolationException($"Expected at least {Position + length} bytes but there are only {_maxPosition} bytes");
}
}
}
+22 -9
View File
@@ -63,17 +63,30 @@ namespace MQTTnet.Formatter
return _buffer;
}
public static int GetLengthOfVariableInteger(uint value)
public static int GetVariableByteIntegerSize(uint value)
{
var result = 0;
var x = value;
do
// From RFC: Table 2.4 Size of Remaining Length field
// 0 (0x00) to 127 (0x7F)
if (value <= 127)
{
x /= 128;
result++;
} while (x > 0);
return 1;
}
return result;
// 128 (0x80, 0x01) to 16 383 (0xFF, 0x7F)
if (value <= 16383)
{
return 2;
}
// 16 384 (0x80, 0x80, 0x01) to 2 097 151 (0xFF, 0xFF, 0x7F)
if (value <= 2097151)
{
return 3;
}
// 2 097 152 (0x80, 0x80, 0x80, 0x01) to 268 435 455 (0xFF, 0xFF, 0xFF, 0x7F)
return 4;
}
public void Reset(int length)
@@ -180,7 +193,7 @@ namespace MQTTnet.Formatter
_buffer[_position] = (byte)(writtenBytes >> 8);
_buffer[_position + 1] = (byte)writtenBytes;
IncreasePosition(writtenBytes + 2);
}
}
+2 -2
View File
@@ -37,7 +37,7 @@ namespace MQTTnet.Formatter
public byte[] ToArray()
{
if (Packet.Count == 0)
if (Payload.Count == 0)
{
return Packet.ToArray();
}
@@ -51,7 +51,7 @@ namespace MQTTnet.Formatter
public ArraySegment<byte> Join()
{
if (Packet.Count == 0)
if (Payload.Count == 0)
{
return Packet;
}
@@ -108,7 +108,7 @@ namespace MQTTnet.Formatter.V3
remainingLength += (uint)publishPacket.Payload.Length;
}
var remainingLengthSize = MqttBufferWriter.GetLengthOfVariableInteger(remainingLength);
var remainingLengthSize = MqttBufferWriter.GetVariableByteIntegerSize(remainingLength);
var headerSize = FixedHeaderSize + remainingLengthSize;
var headerOffset = 5 - headerSize;
@@ -12,6 +12,8 @@ namespace MQTTnet.Formatter.V5
{
public sealed class MqttV5PacketEncoder
{
const int FixedHeaderSize = 1;
readonly MqttBufferWriter _bufferWriter;
readonly MqttV5PropertiesWriter _propertiesWriter = new MqttV5PropertiesWriter(new MqttBufferWriter(1024, 4096));
@@ -40,9 +42,9 @@ namespace MQTTnet.Formatter.V5
remainingLength += (uint)publishPacket.Payload.Length;
}
var remainingLengthSize = MqttBufferWriter.GetLengthOfVariableInteger(remainingLength);
var remainingLengthSize = MqttBufferWriter.GetVariableByteIntegerSize(remainingLength);
var headerSize = 1 + remainingLengthSize;
var headerSize = FixedHeaderSize + remainingLengthSize;
var headerOffset = 5 - headerSize;
// Position cursor on correct offset on beginning of array (has leading 0x0)