baseline: OpenMU upstream b5a0961 (fresh source)
This commit is contained in:
76
tests/MUnique.OpenMU.Network.Tests/ConnectionTests.cs
Normal file
76
tests/MUnique.OpenMU.Network.Tests/ConnectionTests.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
// <copyright file="ConnectionTests.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.Network.Tests;
|
||||
|
||||
using System.IO.Pipelines;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="Connection"/>.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class ConnectionTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests if the connection is disconnected after a malformed packet was received.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task DisconnectedByMalformedPacketReceivedAsync()
|
||||
{
|
||||
var malformedData = new byte[] { 0xDE, 0xAD, 0xBE, 0xEF };
|
||||
var duplexPipe = new DuplexPipe();
|
||||
using var connection = new Connection(duplexPipe, null, null, new NullLogger<Connection>());
|
||||
var disconnected = false;
|
||||
connection.Disconnected += async () => disconnected = true;
|
||||
_ = connection.BeginReceiveAsync();
|
||||
try
|
||||
{
|
||||
await duplexPipe.ReceivePipe.Writer.WriteAsync(malformedData).ConfigureAwait(false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// we need to swallow the exception for this test, so we can check the connected flag afterwards.
|
||||
}
|
||||
|
||||
for (int i = 0; i < 10 && !disconnected; i++)
|
||||
{
|
||||
await Task.Delay(10).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
Assert.That(connection.Connected, Is.False);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if the reader (e.g. SocketConnection) gets an exception when it reads a malformed packet which leads to an exception.
|
||||
/// The consumer (e.g. SocketConnection) will take care to call <see cref="PipeReader.Complete"/> or <see cref="PipeReader.CompleteAsync"/>.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task ExceptionWhenFailingToEncryptSentPacketAsync()
|
||||
{
|
||||
var malformedData = new byte[] { 0xDE, 0xAD, 0xBE, 0xEF };
|
||||
var duplexPipe = new DuplexPipe();
|
||||
using var connection = new Connection(duplexPipe, null, new Xor.PipelinedXor32Encryptor(duplexPipe.Output), new NullLogger<Connection>());
|
||||
|
||||
_ = connection.BeginReceiveAsync();
|
||||
await connection.Output.WriteAsync(malformedData).ConfigureAwait(false);
|
||||
|
||||
Assert.That(
|
||||
async () => await duplexPipe.SendPipe.Reader.ReadAsync().ConfigureAwait(false),
|
||||
Throws.TypeOf<InvalidPacketHeaderException>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if the connection is initially connected.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void InitiallyConnected()
|
||||
{
|
||||
var duplexPipe = new DuplexPipe();
|
||||
using var connection = new Connection(duplexPipe, null, null, new NullLogger<Connection>());
|
||||
Assert.That(connection.Connected, Is.True);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// <copyright file="InvalidPacketHeaderExceptionTest.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.Network.Tests;
|
||||
|
||||
using System.IO.Pipelines;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Tests if <see cref="InvalidPacketHeaderException"/> are thrown when malformed data is read by a <see cref="PacketPipeReaderBase"/>.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class InvalidPacketHeaderExceptionTest
|
||||
{
|
||||
private readonly byte[] _malformedData = { 0xC1, 0x03, 0xFF, 0x00, 0x00, 0x00 };
|
||||
|
||||
/// <summary>
|
||||
/// Tests if the exception is thrown.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task ThrownAsync()
|
||||
{
|
||||
await this.TestExceptionAsync(e => { }).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if <see cref="InvalidPacketHeaderException.Header"/> is assigned correctly.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task TestHeaderAsync()
|
||||
{
|
||||
await this.TestExceptionAsync(e => Assert.That(e.Header, Is.EquivalentTo(new byte[] { 0x00, 0x00, 0x00 }))).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if <see cref="InvalidPacketHeaderException.Position"/> is assigned correctly.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task TestPositionAsync()
|
||||
{
|
||||
await this.TestExceptionAsync(e => Assert.That(e.Position, Is.EqualTo(3))).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if <see cref="InvalidPacketHeaderException.BufferContent"/> is assigned correctly.
|
||||
/// </summary>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task TestBufferContentAsync()
|
||||
{
|
||||
await this.TestExceptionAsync(e => Assert.That(e.BufferContent, Is.EquivalentTo(this._malformedData))).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async ValueTask TestExceptionAsync(Action<InvalidPacketHeaderException> check)
|
||||
{
|
||||
bool thrown = false;
|
||||
var duplexPipe = new DuplexPipe(new PipeOptions(pauseWriterThreshold: 1, resumeWriterThreshold: 1));
|
||||
using var connection = new Connection(duplexPipe, null, new Xor.PipelinedXor32Encryptor(duplexPipe.Output), new NullLogger<Connection>());
|
||||
_ = connection.BeginReceiveAsync();
|
||||
|
||||
try
|
||||
{
|
||||
_ = await duplexPipe.ReceivePipe.Writer.WriteAsync(this._malformedData).ConfigureAwait(false);
|
||||
}
|
||||
catch (InvalidPacketHeaderException e)
|
||||
{
|
||||
thrown = true;
|
||||
check(e);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Assert.Fail($"Wrong exception type {e}", e);
|
||||
}
|
||||
|
||||
Assert.That(thrown);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
// <copyright file="IpAddressResolverFactoryTests.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.Network.Tests;
|
||||
|
||||
using System.Net;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for <see cref="IpAddressResolverFactory"/>.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
[NonParallelizable]
|
||||
public class IpAddressResolverFactoryTests
|
||||
{
|
||||
private readonly IPAddress _expectedLoopbackAddress = IPAddress.Parse("127.127.127.127");
|
||||
|
||||
private string? _originalResolveIpEnvironmentVariable;
|
||||
private string? _originalAspNetCoreEnvironmentVariable;
|
||||
|
||||
/// <summary>
|
||||
/// Captures and clears the environment variables which influence resolver determination.
|
||||
/// </summary>
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
this._originalResolveIpEnvironmentVariable = Environment.GetEnvironmentVariable("RESOLVE_IP");
|
||||
this._originalAspNetCoreEnvironmentVariable = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
||||
Environment.SetEnvironmentVariable("RESOLVE_IP", null);
|
||||
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restores the environment variables which were changed during a test.
|
||||
/// </summary>
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("RESOLVE_IP", this._originalResolveIpEnvironmentVariable);
|
||||
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", this._originalAspNetCoreEnvironmentVariable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if runtime reconfiguration is ignored when the resolver was configured by startup parameters.
|
||||
/// </summary>
|
||||
/// <returns>The asynchronous operation.</returns>
|
||||
[Test]
|
||||
public async Task ResolverConfiguredByStartupParameterCannotBeOverriddenAsync()
|
||||
{
|
||||
var resolver = (ConfigurableIpResolver)IpAddressResolverFactory.CreateIpResolver(new[] { "-resolveIP:loopback" }, (IpResolverType.Public, null), new NullLoggerFactory());
|
||||
|
||||
resolver.Configure(IpResolverType.Custom, "1.2.3.4");
|
||||
var resolvedAddress = await resolver.ResolveIPv4Async().ConfigureAwait(false);
|
||||
|
||||
Assert.That(resolvedAddress, Is.EqualTo(this._expectedLoopbackAddress));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if runtime reconfiguration is ignored when the resolver was configured by environment variable.
|
||||
/// </summary>
|
||||
/// <returns>The asynchronous operation.</returns>
|
||||
[Test]
|
||||
public async Task ResolverConfiguredByEnvironmentVariableCannotBeOverriddenAsync()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("RESOLVE_IP", "loopback");
|
||||
var resolver = (ConfigurableIpResolver)IpAddressResolverFactory.CreateIpResolver(Array.Empty<string>(), (IpResolverType.Public, null), new NullLoggerFactory());
|
||||
|
||||
resolver.Configure(IpResolverType.Custom, "1.2.3.4");
|
||||
var resolvedAddress = await resolver.ResolveIPv4Async().ConfigureAwait(false);
|
||||
|
||||
Assert.That(resolvedAddress, Is.EqualTo(this._expectedLoopbackAddress));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if runtime reconfiguration still works when the resolver was configured by persisted settings.
|
||||
/// </summary>
|
||||
/// <returns>The asynchronous operation.</returns>
|
||||
[Test]
|
||||
public async Task ResolverConfiguredByPersistedSettingsCanBeOverriddenAsync()
|
||||
{
|
||||
var resolver = (ConfigurableIpResolver)IpAddressResolverFactory.CreateIpResolver(Array.Empty<string>(), (IpResolverType.Loopback, null), new NullLoggerFactory());
|
||||
|
||||
resolver.Configure(IpResolverType.Custom, "1.2.3.4");
|
||||
var resolvedAddress = await resolver.ResolveIPv4Async().ConfigureAwait(false);
|
||||
|
||||
Assert.That(resolvedAddress, Is.EqualTo(IPAddress.Parse("1.2.3.4")));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<WarningsAsErrors>nullable;CS4014;VSTHRD110;VSTHRD100</WarningsAsErrors>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DocumentationFile>bin\Debug\MUnique.OpenMU.Network.Tests.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DocumentationFile>bin\Release\MUnique.OpenMU.Network.Tests.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\src\SharedAssemblyInfo.cs" Link="Properties\SharedAssemblyInfo.cs" />
|
||||
<Compile Include="..\..\src\SharedGlobalUsings.cs" Link="SharedGlobalUsings.cs" />
|
||||
<Compile Include="..\SharedTestUsings.cs" Link="SharedTestUsings.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="..\..\src\stylecop.json" Link="stylecop.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\src\.editorconfig" Link=".editorconfig" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" />
|
||||
<PackageReference Include="NUnit" />
|
||||
<PackageReference Include="NUnit3TestAdapter" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Network\MUnique.OpenMU.Network.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
41
tests/MUnique.OpenMU.Network.Tests/PacketTwisterTest.cs
Normal file
41
tests/MUnique.OpenMU.Network.Tests/PacketTwisterTest.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
// <copyright file="PacketTwisterTest.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.Network.Tests;
|
||||
|
||||
using MUnique.OpenMU.Network.PacketTwister;
|
||||
|
||||
/// <summary>
|
||||
/// Tests for the <see cref="PacketTwistRunner"/>.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class PacketTwisterTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests encryption and decryption using the <see cref="PacketTwistRunner"/>.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void EncryptDecryptWithPacketTwister()
|
||||
{
|
||||
var decrypted = Convert.FromBase64String("w7gAudHEjjSP53H6Rkp3oXj7B9z+rVDR2f0Is4bvsIsUL3RM/aTDB2FX9YG3Hkboy1Z1JThot558MeDTvNuunzfl5RbWK6TTOP97prjPGbq3IOcweopTq3fVz8vD8EuFqVVJ0jgvEZ+xoe047RHmrRgmG5zzfSWtkTmeAVzZD0i09f1jhUeBiA5HfticGr5m7iGzndSvkSwvm0D/kRBD15GlhPgTgyfQpJONrP5NEHd7NxI6JnJzBQ==");
|
||||
var packetTwister = new PacketTwister.PacketTwistRunner();
|
||||
for (byte packetType = 0; packetType < byte.MaxValue; packetType++)
|
||||
{
|
||||
decrypted[2] = packetType;
|
||||
var result = decrypted.ToArray();
|
||||
packetTwister.Encrypt(result);
|
||||
packetTwister.Decrypt(result);
|
||||
CompareArrays(decrypted, result);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CompareArrays(byte[] expected, byte[] actual)
|
||||
{
|
||||
Assert.That(actual.Length, Is.EqualTo(expected.Length));
|
||||
for (int i = 0; i < actual.Length; i++)
|
||||
{
|
||||
Assert.That(actual[i], Is.EqualTo(expected[i]), "index {0}, packet type {1}", i, expected[expected.GetPacketHeaderSize()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
160
tests/MUnique.OpenMU.Network.Tests/PipelinedDecryptorTests.cs
Normal file
160
tests/MUnique.OpenMU.Network.Tests/PipelinedDecryptorTests.cs
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,137 @@
|
||||
// <copyright file="PipelinedEncryptDecryptCycleTests.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.Network.Tests;
|
||||
|
||||
using System.Buffers;
|
||||
using System.IO.Pipelines;
|
||||
using MUnique.OpenMU.Network.SimpleModulus;
|
||||
using MUnique.OpenMU.Network.Xor;
|
||||
|
||||
/// <summary>
|
||||
/// Tests the cycle of encrypting and decrypting a packet purely due pipes.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class PipelinedEncryptDecryptCycleTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests the encryption and decryption cycle of C3-packets from client to server.
|
||||
/// These packets get encrypted first by <see cref="PipelinedXor32Encryptor"/>, then by <see cref="PipelinedSimpleModulusEncryptor"/> using client-side keys.
|
||||
/// Then it gets decrypted by the <see cref="PipelinedSimpleModulusDecryptor"/> using server-side keys and finally by the <see cref="PipelinedXor32Decryptor"/>.
|
||||
/// </summary>
|
||||
/// <returns>The task.</returns>
|
||||
[Test]
|
||||
public async Task ClientToServerC3Async()
|
||||
{
|
||||
var packet = Convert.FromBase64String("w7kxFgK8hYpGGLgdXe7ZpTZViB+r3sRI3YSqZs7/Mh5Vmh2mXqs+3dqkvURmXrL57ASs+FkJz/236Tl9ER67R+WZyMLRMkeLF6tEBiB/4X7SsXrKUznES8of73RxwMy76HZezJbvJ7m9IOGuxcjcNwe6q1+k8fOs1Hz3sULSGlbfiB6qIBXo4onADTNYFoYCQrdtthVsF/aDsvcZ93V36gaKzzyqMhby0sjV4+TAU7719W6LZWNAcnA=");
|
||||
await this.EncryptDecryptFromClientToServerAsync(packet).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the encryption of a packet where the final block doesn't have maximum size.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The test uses a real ping packet which was captured from a real game client.
|
||||
/// </remarks>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task ClientToServerC3WithNonMaximalFinalBlockSizeAsync()
|
||||
{
|
||||
var packet = new byte[] { 195, 12, 14, 0, 1, 51, 254, 39, 0, 0, 0, 0 };
|
||||
await this.EncryptDecryptFromClientToServerAsync(packet).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the encryption of a C3 packet where the size is lower than the maximum block size.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The test uses a real ping packet which was captured from a real game client.
|
||||
/// </remarks>
|
||||
/// <returns>The async task.</returns>
|
||||
[Test]
|
||||
public async Task ClientToServerC3WithSmallPacketAsync()
|
||||
{
|
||||
var packet = new byte[] { 195, 5, 14, 0, 1 };
|
||||
await this.EncryptDecryptFromClientToServerAsync(packet).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the encryption and decryption cycle of C1-packets from client to server.
|
||||
/// These packets get encrypted first by <see cref="PipelinedXor32Encryptor"/>, then <see cref="PipelinedSimpleModulusEncryptor"/> just forwards then as-is.
|
||||
/// Then the <see cref="PipelinedSimpleModulusDecryptor"/> forwards them as well and finally it gets decrypted by the <see cref="PipelinedXor32Decryptor"/>.
|
||||
/// </summary>
|
||||
/// <returns>The task.</returns>
|
||||
[Test]
|
||||
public async Task ClientToServerC1Async()
|
||||
{
|
||||
var packet = new byte[] { 0xC1, 0x06, 0x11, 0x01, 0x02, 0x03 };
|
||||
await this.EncryptDecryptFromClientToServerAsync(packet).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the encryption and decryption cycle of C3-packets from server to client.
|
||||
/// These packets get encrypted first by the <see cref="PipelinedSimpleModulusEncryptor"/> using server-side keys.
|
||||
/// On the client side it gets decrypted by the <see cref="PipelinedSimpleModulusDecryptor"/> using client-side keys.
|
||||
/// </summary>
|
||||
/// <returns>The task.</returns>
|
||||
[Test]
|
||||
public async Task ServerToClientC3Async()
|
||||
{
|
||||
var packet = Convert.FromBase64String("w7kxFgK8hYpGGLgdXe7ZpTZViB+r3sRI3YSqZs7/Mh5Vmh2mXqs+3dqkvURmXrL57ASs+FkJz/236Tl9ER67R+WZyMLRMkeLF6tEBiB/4X7SsXrKUznES8of73RxwMy76HZezJbvJ7m9IOGuxcjcNwe6q1+k8fOs1Hz3sULSGlbfiB6qIBXo4onADTNYFoYCQrdtthVsF/aDsvcZ93V36gaKzzyqMhby0sjV4+TAU7719W6LZWNAcnA=");
|
||||
await this.EncryptDecryptFromServerToClientAsync(packet).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the encryption and decryption cycle of C1-packets from server to client.
|
||||
/// These packets are not encrypted at all, so all involved simple modulus encryptor/decryptors just forward them.
|
||||
/// </summary>
|
||||
/// <returns>The task.</returns>
|
||||
[Test]
|
||||
public async Task ServerToClientC1Async()
|
||||
{
|
||||
var packet = new byte[] { 0xC1, 0x06, 0x11, 0x01, 0x02, 0x03 };
|
||||
await this.EncryptDecryptFromServerToClientAsync(packet).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the encryption-decryption cycle for the packet from server to client. The specified packet must be the same after the packet has passed this cycle.
|
||||
/// Packets from server to client are never encrypted by Xor32, so these encryptor/decryptors are not involved here.
|
||||
/// </summary>
|
||||
/// <param name="packet">The packet.</param>
|
||||
/// <returns>The task.</returns>
|
||||
private async Task EncryptDecryptFromServerToClientAsync(byte[] packet)
|
||||
{
|
||||
// this pipe connects the encryptor with the decryptor. You can imagine this as the server-to-client pipe of a network socket, for example.
|
||||
var pipe = new Pipe();
|
||||
|
||||
var encryptor = new PipelinedSimpleModulusEncryptor(pipe.Writer);
|
||||
var decryptor = new PipelinedSimpleModulusDecryptor(pipe.Reader, PipelinedSimpleModulusDecryptor.DefaultClientKey);
|
||||
encryptor.Writer.Write(packet);
|
||||
await encryptor.Writer.FlushAsync().ConfigureAwait(false);
|
||||
var readResult = await decryptor.Reader.ReadAsync().ConfigureAwait(false);
|
||||
|
||||
var result = readResult.Buffer.ToArray();
|
||||
Assert.That(result, Is.EquivalentTo(packet));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the encryption-decryption cycle for the packet. The specified packet must be the same after the packet has passed this cycle.
|
||||
/// </summary>
|
||||
/// <param name="packet">The packet.</param>
|
||||
/// <returns>The async task.</returns>
|
||||
private async Task EncryptDecryptFromClientToServerAsync(byte[] packet)
|
||||
{
|
||||
// this pipe connects the encryptor with the decryptor. You can imagine this as the client-to-server pipe of a network socket, for example.
|
||||
var pipe = new Pipe();
|
||||
|
||||
var encryptor = new PipelinedXor32Encryptor(new PipelinedSimpleModulusEncryptor(pipe.Writer, PipelinedSimpleModulusEncryptor.DefaultClientKey).Writer);
|
||||
var decryptor = new PipelinedXor32Decryptor(new PipelinedSimpleModulusDecryptor(pipe.Reader).Reader);
|
||||
encryptor.Writer.Write(packet);
|
||||
await encryptor.Writer.FlushAsync().ConfigureAwait(false);
|
||||
var readResult = await decryptor.Reader.ReadAsync().ConfigureAwait(false);
|
||||
|
||||
var result = readResult.Buffer.ToArray();
|
||||
Assert.That(result, Is.EquivalentTo(packet));
|
||||
}
|
||||
}
|
||||
107
tests/MUnique.OpenMU.Network.Tests/PipelinedEncryptorTests.cs
Normal file
107
tests/MUnique.OpenMU.Network.Tests/PipelinedEncryptorTests.cs
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,10 @@
|
||||
// <copyright file="AssemblyInfo.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("MUnique.OpenMU.Network.Tests")]
|
||||
162
tests/MUnique.OpenMU.Network.Tests/SocketConnectionTest.cs
Normal file
162
tests/MUnique.OpenMU.Network.Tests/SocketConnectionTest.cs
Normal file
@@ -0,0 +1,162 @@
|
||||
// <copyright file="SocketConnectionTest.cs" company="MUnique">
|
||||
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
|
||||
// </copyright>
|
||||
|
||||
namespace MUnique.OpenMU.Network.Tests;
|
||||
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Pipelines.Sockets.Unofficial;
|
||||
|
||||
/// <summary>
|
||||
/// Test of the async connection implementation.
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
[Ignore("It's using real sockets")]
|
||||
public class SocketConnectionTest
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests the receive function with a pipelined connection object.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestReceivePipelined()
|
||||
{
|
||||
this.TestReceivePipelined(socket => new Connection(SocketConnection.Create(socket), null, null, new NullLogger<Connection>()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the receive function with a pipelined connection object with encryptor/decryptor.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestReceivePipelinedWithEncryption()
|
||||
{
|
||||
this.TestReceivePipelined(socket =>
|
||||
{
|
||||
var socketConnection = SocketConnection.Create(socket);
|
||||
return new Connection(socketConnection, new PipelinedDecryptor(socketConnection.Input), new PipelinedEncryptor(socketConnection.Output), new NullLogger<Connection>());
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if the connection is disconnected after sending invalid data.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestDisconnectOnInvalidHeaderSentAsync()
|
||||
{
|
||||
IConnection? connection = null;
|
||||
var server = new TcpListener(IPAddress.Any, 5000);
|
||||
server.Start();
|
||||
try
|
||||
{
|
||||
server.BeginAcceptSocket(
|
||||
asyncResult =>
|
||||
{
|
||||
var clientSocket = server.EndAcceptSocket(asyncResult);
|
||||
var socketConnection = SocketConnection.Create(clientSocket);
|
||||
connection = new Connection(socketConnection, new PipelinedDecryptor(socketConnection.Input), new PipelinedEncryptor(socketConnection.Output), new NullLogger<Connection>());
|
||||
}, null);
|
||||
|
||||
using var client = new TcpClient("127.0.0.1", 5000);
|
||||
while (connection == null)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
|
||||
#pragma warning disable 4014
|
||||
connection.BeginReceiveAsync();
|
||||
#pragma warning restore 4014
|
||||
|
||||
var packet = new byte[22222];
|
||||
packet[0] = 0xDE;
|
||||
packet[1] = 0xAD;
|
||||
packet[2] = 0xBE;
|
||||
packet[3] = 0xAF;
|
||||
await connection.Output.WriteAsync(packet).ConfigureAwait(false);
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
|
||||
Assert.That(connection.Connected, Is.False);
|
||||
}
|
||||
finally
|
||||
{
|
||||
server.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests if the connection is disconnected after receiving invalid data.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestDisconnectOnInvalidHeaderReceived()
|
||||
{
|
||||
var server = new TcpListener(IPAddress.Any, 5000);
|
||||
server.Start();
|
||||
try
|
||||
{
|
||||
server.BeginAcceptSocket(
|
||||
asyncResult =>
|
||||
{
|
||||
var clientSocket = server.EndAcceptSocket(asyncResult);
|
||||
var packet = new byte[] { 0xDE, 0xAD, 0xBE, 0xEF, 0, 0, 0, 0, 0, 0 };
|
||||
clientSocket.BeginSend(packet, 0, packet.Length, SocketFlags.None, null, null);
|
||||
}, null);
|
||||
|
||||
using var client = new TcpClient("127.0.0.1", 5000);
|
||||
var socketConnection = SocketConnection.Create(client.Client);
|
||||
var connection = new Connection(socketConnection, new PipelinedDecryptor(socketConnection.Input), new PipelinedEncryptor(socketConnection.Output), new NullLogger<Connection>());
|
||||
|
||||
_ = connection.BeginReceiveAsync();
|
||||
|
||||
Thread.Sleep(100);
|
||||
Assert.That(connection.Connected, Is.False);
|
||||
}
|
||||
finally
|
||||
{
|
||||
server.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the receiving of data with any <see cref="IConnection"/> implementation.
|
||||
/// </summary>
|
||||
/// <param name="connectionCreator">The connection creator.</param>
|
||||
private void TestReceivePipelined(Func<Socket, IConnection> connectionCreator)
|
||||
{
|
||||
const int maximumPacketCount = 1000;
|
||||
|
||||
IConnection? connection = null;
|
||||
var server = new TcpListener(IPAddress.Any, 5000);
|
||||
server.Start();
|
||||
server.BeginAcceptSocket(
|
||||
asyncResult =>
|
||||
{
|
||||
var clientSocket = server.EndAcceptSocket(asyncResult);
|
||||
connection = connectionCreator(clientSocket);
|
||||
}, null);
|
||||
using (var client = new TcpClient("127.0.0.1", 5000))
|
||||
{
|
||||
while (connection == null)
|
||||
{
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
|
||||
int packetCount = 0;
|
||||
connection.PacketReceived += async p => Interlocked.Increment(ref packetCount);
|
||||
_ = connection.BeginReceiveAsync();
|
||||
|
||||
var packet = new byte[] { 0xC1, 10, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
for (int i = 0; i < maximumPacketCount; i++)
|
||||
{
|
||||
client.Client.BeginSend(packet, 0, packet.Length, SocketFlags.None, null, null);
|
||||
}
|
||||
|
||||
while (packetCount < maximumPacketCount)
|
||||
{
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
server.Stop();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user