aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBond_009 <bond.009@outlook.com>2021-03-13 21:12:11 +0100
committerBond_009 <bond.009@outlook.com>2021-03-13 21:12:11 +0100
commitf9640f43663fdf443c130f61cab3521fcb1c7823 (patch)
tree20b8f23b553418bd8183b0e303917d1155d550e0
parente8b18e5f8fe87f981b11237d24032ab11589bcd2 (diff)
Rewrite HdHomerunManager.ParseReturnMessage
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs75
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/LiveTv/HdHomerunManagerTests.cs209
2 files changed, 244 insertions, 40 deletions
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
index 9c113bc7c..a7fda1d72 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunManager.cs
@@ -130,9 +130,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
int receivedBytes = await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
- ParseReturnMessage(buffer, receivedBytes, out string returnVal);
-
- return string.Equals(returnVal, "none", StringComparison.OrdinalIgnoreCase);
+ return VerifyReturnValueOfGetSet(buffer.AsSpan(receivedBytes), "none");
}
finally
{
@@ -173,7 +171,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
int receivedBytes = await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
// parse response to make sure it worked
- if (!ParseReturnMessage(buffer, receivedBytes, out _))
+ if (!TryGetReturnValueOfGetSet(buffer.AsSpan(0, receivedBytes), out _))
{
continue;
}
@@ -185,7 +183,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
receivedBytes = await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
// parse response to make sure it worked
- if (!ParseReturnMessage(buffer, receivedBytes, out _))
+ if (!TryGetReturnValueOfGetSet(buffer.AsSpan(0, receivedBytes), out _))
{
await ReleaseLockkey(_tcpClient, lockKeyValue).ConfigureAwait(false);
continue;
@@ -199,7 +197,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
receivedBytes = await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
// parse response to make sure it worked
- if (!ParseReturnMessage(buffer, receivedBytes, out _))
+ if (!TryGetReturnValueOfGetSet(buffer.AsSpan(0, receivedBytes), out _))
{
await ReleaseLockkey(_tcpClient, lockKeyValue).ConfigureAwait(false);
continue;
@@ -239,7 +237,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
int receivedBytes = await stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false);
// parse response to make sure it worked
- if (!ParseReturnMessage(buffer, receivedBytes, out _))
+ if (!TryGetReturnValueOfGetSet(buffer.AsSpan(0, receivedBytes), out _))
{
return;
}
@@ -355,60 +353,65 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return offset + 4;
}
- internal static bool ParseReturnMessage(byte[] buf, int numBytes, out string returnVal)
+ internal static bool VerifyReturnValueOfGetSet(ReadOnlySpan<byte> buffer, string expected)
{
- returnVal = string.Empty;
+ return TryGetReturnValueOfGetSet(buffer, out var value)
+ && string.Equals(Encoding.UTF8.GetString(value), expected, StringComparison.OrdinalIgnoreCase);
+ }
- if (numBytes < 4)
+ internal static bool TryGetReturnValueOfGetSet(ReadOnlySpan<byte> buffer, out ReadOnlySpan<byte> value)
+ {
+ value = ReadOnlySpan<byte>.Empty;
+
+ if (buffer.Length < 8)
{
return false;
}
- var flipEndian = BitConverter.IsLittleEndian;
- int offset = 0;
- byte[] msgTypeBytes = new byte[2];
- Buffer.BlockCopy(buf, offset, msgTypeBytes, 0, msgTypeBytes.Length);
-
- if (flipEndian)
+ uint crc = BinaryPrimitives.ReadUInt32LittleEndian(buffer[^4..]);
+ if (crc != Crc32.Compute(buffer[..^4]))
{
- Array.Reverse(msgTypeBytes);
+ return false;
}
- var msgType = BitConverter.ToUInt16(msgTypeBytes, 0);
- offset += 2;
-
- if (msgType != GetSetReply)
+ if (BinaryPrimitives.ReadUInt16BigEndian(buffer) != GetSetReply)
{
return false;
}
- byte[] msgLengthBytes = new byte[2];
- Buffer.BlockCopy(buf, offset, msgLengthBytes, 0, msgLengthBytes.Length);
- if (flipEndian)
+ var msgLength = BinaryPrimitives.ReadUInt16BigEndian(buffer.Slice(2));
+ if (buffer.Length != 2 + 2 + 4 + msgLength)
{
- Array.Reverse(msgLengthBytes);
+ return false;
}
- var msgLength = BitConverter.ToUInt16(msgLengthBytes, 0);
- offset += 2;
-
- if (numBytes < msgLength + 8)
+ var offset = 4;
+ if (buffer[offset++] != GetSetName)
{
return false;
}
- offset++; // Name Tag
-
- var nameLength = buf[offset++];
+ var nameLength = buffer[offset++];
+ if (buffer.Length < 4 + 1 + offset + nameLength)
+ {
+ return false;
+ }
- // skip the name field to get to value for return
offset += nameLength;
- offset++; // Value Tag
+ if (buffer[offset++] != GetSetValue)
+ {
+ return false;
+ }
- var valueLength = buf[offset++];
+ var valueLength = buffer[offset++];
+ if (buffer.Length < 4 + offset + valueLength)
+ {
+ return false;
+ }
- returnVal = Encoding.UTF8.GetString(buf, offset, valueLength - 1); // remove null terminator
+ // remove null terminator
+ value = buffer.Slice(offset, valueLength - 1);
return true;
}
}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/HdHomerunManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/HdHomerunManagerTests.cs
index 355cfa641..c404e6ed5 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/LiveTv/HdHomerunManagerTests.cs
+++ b/tests/Jellyfin.Server.Implementations.Tests/LiveTv/HdHomerunManagerTests.cs
@@ -1,4 +1,5 @@
using System;
+using System.Text;
using Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun;
using Xunit;
@@ -105,9 +106,9 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
}
[Fact]
- public void ParseReturnMessage_Valid_Success()
+ public void TryGetReturnValueOfGetSet_Valid_Success()
{
- ReadOnlySpan<byte> packet = stackalloc byte[]
+ ReadOnlySpan<byte> packet = new byte[]
{
0, 5,
0, 20,
@@ -118,8 +119,208 @@ namespace Jellyfin.Server.Implementations.Tests.LiveTv
0x7d, 0xa3, 0xa3, 0xf3
};
- Assert.True(HdHomerunManager.ParseReturnMessage(packet.ToArray(), packet.Length, out var value));
- Assert.Equal("value", value);
+ Assert.True(HdHomerunManager.TryGetReturnValueOfGetSet(packet, out var value));
+ Assert.Equal("value", Encoding.UTF8.GetString(value));
+ }
+
+ [Fact]
+ public void TryGetReturnValueOfGetSet_InvalidPacketType_False()
+ {
+ ReadOnlySpan<byte> packet = new byte[]
+ {
+ 0, 4,
+ 0, 20,
+ 3,
+ 10, (byte)'/', (byte)'t', (byte)'u', (byte)'n', (byte)'e', (byte)'r', (byte)'0', (byte)'/', (byte)'N', 0,
+ 4,
+ 6, (byte)'v', (byte)'a', (byte)'l', (byte)'u', (byte)'e', 0,
+ 0x7d, 0xa3, 0xa3, 0xf3
+ };
+
+ Assert.False(HdHomerunManager.TryGetReturnValueOfGetSet(packet, out _));
+ }
+
+ [Fact]
+ public void TryGetReturnValueOfGetSet_InvalidCrc_False()
+ {
+ ReadOnlySpan<byte> packet = new byte[]
+ {
+ 0, 5,
+ 0, 20,
+ 3,
+ 10, (byte)'/', (byte)'t', (byte)'u', (byte)'n', (byte)'e', (byte)'r', (byte)'0', (byte)'/', (byte)'N', 0,
+ 4,
+ 6, (byte)'v', (byte)'a', (byte)'l', (byte)'u', (byte)'e', 0,
+ 0x7d, 0xa3, 0xa3, 0xf4
+ };
+
+ Assert.False(HdHomerunManager.TryGetReturnValueOfGetSet(packet, out _));
+ }
+
+ [Fact]
+ public void TryGetReturnValueOfGetSet_InvalidPacket_False()
+ {
+ ReadOnlySpan<byte> packet = new byte[]
+ {
+ 0, 5,
+ 0, 20,
+ 0x7d, 0xa3, 0xa3
+ };
+
+ Assert.False(HdHomerunManager.TryGetReturnValueOfGetSet(packet, out _));
+ }
+
+ [Fact]
+ public void TryGetReturnValueOfGetSet_TooSmallMessageLength_False()
+ {
+ ReadOnlySpan<byte> packet = new byte[]
+ {
+ 0, 5,
+ 0, 19,
+ 3,
+ 10, (byte)'/', (byte)'t', (byte)'u', (byte)'n', (byte)'e', (byte)'r', (byte)'0', (byte)'/', (byte)'N', 0,
+ 4,
+ 6, (byte)'v', (byte)'a', (byte)'l', (byte)'u', (byte)'e', 0,
+ 0x25, 0x25, 0x44, 0x9a
+ };
+
+ Assert.False(HdHomerunManager.TryGetReturnValueOfGetSet(packet, out _));
+ }
+
+ [Fact]
+ public void TryGetReturnValueOfGetSet_TooLargeMessageLength_False()
+ {
+ ReadOnlySpan<byte> packet = new byte[]
+ {
+ 0, 5,
+ 0, 21,
+ 3,
+ 10, (byte)'/', (byte)'t', (byte)'u', (byte)'n', (byte)'e', (byte)'r', (byte)'0', (byte)'/', (byte)'N', 0,
+ 4,
+ 6, (byte)'v', (byte)'a', (byte)'l', (byte)'u', (byte)'e', 0,
+ 0xe3, 0x20, 0x79, 0x6c
+ };
+
+ Assert.False(HdHomerunManager.TryGetReturnValueOfGetSet(packet, out _));
+ }
+
+ [Fact]
+ public void TryGetReturnValueOfGetSet_TooLargeNameLength_False()
+ {
+ ReadOnlySpan<byte> packet = new byte[]
+ {
+ 0, 5,
+ 0, 20,
+ 3,
+ 20, (byte)'/', (byte)'t', (byte)'u', (byte)'n', (byte)'e', (byte)'r', (byte)'0', (byte)'/', (byte)'N', 0,
+ 4,
+ 6, (byte)'v', (byte)'a', (byte)'l', (byte)'u', (byte)'e', 0,
+ 0xe1, 0x8e, 0x9c, 0x74
+ };
+
+ Assert.False(HdHomerunManager.TryGetReturnValueOfGetSet(packet, out _));
+ }
+
+ [Fact]
+ public void TryGetReturnValueOfGetSet_InvalidGetSetNameTag_False()
+ {
+ ReadOnlySpan<byte> packet = new byte[]
+ {
+ 0, 5,
+ 0, 20,
+ 4,
+ 10, (byte)'/', (byte)'t', (byte)'u', (byte)'n', (byte)'e', (byte)'r', (byte)'0', (byte)'/', (byte)'N', 0,
+ 4,
+ 6, (byte)'v', (byte)'a', (byte)'l', (byte)'u', (byte)'e', 0,
+ 0xee, 0x05, 0xe7, 0x12
+ };
+
+ Assert.False(HdHomerunManager.TryGetReturnValueOfGetSet(packet, out _));
+ }
+
+ [Fact]
+ public void TryGetReturnValueOfGetSet_InvalidGetSetValueTag_False()
+ {
+ ReadOnlySpan<byte> packet = new byte[]
+ {
+ 0, 5,
+ 0, 20,
+ 3,
+ 10, (byte)'/', (byte)'t', (byte)'u', (byte)'n', (byte)'e', (byte)'r', (byte)'0', (byte)'/', (byte)'N', 0,
+ 3,
+ 6, (byte)'v', (byte)'a', (byte)'l', (byte)'u', (byte)'e', 0,
+ 0x64, 0xaa, 0x66, 0xf9
+ };
+
+ Assert.False(HdHomerunManager.TryGetReturnValueOfGetSet(packet, out _));
+ }
+
+ [Fact]
+ public void TryGetReturnValueOfGetSet_TooLargeValueLength_False()
+ {
+ ReadOnlySpan<byte> packet = new byte[]
+ {
+ 0, 5,
+ 0, 20,
+ 3,
+ 10, (byte)'/', (byte)'t', (byte)'u', (byte)'n', (byte)'e', (byte)'r', (byte)'0', (byte)'/', (byte)'N', 0,
+ 4,
+ 7, (byte)'v', (byte)'a', (byte)'l', (byte)'u', (byte)'e', 0,
+ 0xc9, 0xa8, 0xd4, 0x55
+ };
+
+ Assert.False(HdHomerunManager.TryGetReturnValueOfGetSet(packet, out _));
+ }
+
+ [Fact]
+ public void VerifyReturnValueOfGetSet_Valid_True()
+ {
+ ReadOnlySpan<byte> packet = new byte[]
+ {
+ 0, 5,
+ 0, 20,
+ 3,
+ 10, (byte)'/', (byte)'t', (byte)'u', (byte)'n', (byte)'e', (byte)'r', (byte)'0', (byte)'/', (byte)'N', 0,
+ 4,
+ 6, (byte)'v', (byte)'a', (byte)'l', (byte)'u', (byte)'e', 0,
+ 0x7d, 0xa3, 0xa3, 0xf3
+ };
+
+ Assert.True(HdHomerunManager.VerifyReturnValueOfGetSet(packet, "value"));
+ }
+
+ [Fact]
+ public void VerifyReturnValueOfGetSet_WrongValue_False()
+ {
+ ReadOnlySpan<byte> packet = new byte[]
+ {
+ 0, 5,
+ 0, 20,
+ 3,
+ 10, (byte)'/', (byte)'t', (byte)'u', (byte)'n', (byte)'e', (byte)'r', (byte)'0', (byte)'/', (byte)'N', 0,
+ 4,
+ 6, (byte)'v', (byte)'a', (byte)'l', (byte)'u', (byte)'e', 0,
+ 0x7d, 0xa3, 0xa3, 0xf3
+ };
+
+ Assert.False(HdHomerunManager.VerifyReturnValueOfGetSet(packet, "none"));
+ }
+
+ [Fact]
+ public void VerifyReturnValueOfGetSet_InvalidPacket_False()
+ {
+ ReadOnlySpan<byte> packet = new byte[]
+ {
+ 0, 4,
+ 0, 20,
+ 3,
+ 10, (byte)'/', (byte)'t', (byte)'u', (byte)'n', (byte)'e', (byte)'r', (byte)'0', (byte)'/', (byte)'N', 0,
+ 4,
+ 6, (byte)'v', (byte)'a', (byte)'l', (byte)'u', (byte)'e', 0,
+ 0x7d, 0xa3, 0xa3, 0xf3
+ };
+
+ Assert.False(HdHomerunManager.VerifyReturnValueOfGetSet(packet, "value"));
}
}
}