diff --git a/.gitignore b/.gitignore index 25e7ded..ece189d 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,5 @@ UpgradeLog.htm *.svclog mono_crash.*.json mono_crash.*.blob + +autobahn/reports/* \ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props index 60f38ba..f89a17b 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -2,7 +2,7 @@ true - @@ -13,9 +13,8 @@ - + - @@ -28,4 +27,4 @@ - + \ No newline at end of file diff --git a/SimpleR.sln b/SimpleR.sln index 6ee7df7..518a23b 100644 --- a/SimpleR.sln +++ b/SimpleR.sln @@ -64,6 +64,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ext", "ext", "{813A63E0-FB3 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleR.Ocpp", "ext\SimpleR.Ocpp\SimpleR.Ocpp.csproj", "{531643BE-44A4-404B-A3BB-6C44BC7C49D9}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "autobahn", "autobahn", "{D4D520AA-4FE3-4F44-857B-B4AC0AF37E5A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleR.Authobahn.Server", "autobahn\server\SimpleR.Authobahn.Server.csproj", "{2D7F07BA-59E0-4B6D-8AB2-5AF9962AAD13}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -144,6 +148,12 @@ Global {531643BE-44A4-404B-A3BB-6C44BC7C49D9}.Release|Any CPU.Build.0 = Release|Any CPU {531643BE-44A4-404B-A3BB-6C44BC7C49D9}.Publish|Any CPU.ActiveCfg = Debug|Any CPU {531643BE-44A4-404B-A3BB-6C44BC7C49D9}.Publish|Any CPU.Build.0 = Debug|Any CPU + {2D7F07BA-59E0-4B6D-8AB2-5AF9962AAD13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2D7F07BA-59E0-4B6D-8AB2-5AF9962AAD13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2D7F07BA-59E0-4B6D-8AB2-5AF9962AAD13}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2D7F07BA-59E0-4B6D-8AB2-5AF9962AAD13}.Release|Any CPU.Build.0 = Release|Any CPU + {2D7F07BA-59E0-4B6D-8AB2-5AF9962AAD13}.Publish|Any CPU.ActiveCfg = Debug|Any CPU + {2D7F07BA-59E0-4B6D-8AB2-5AF9962AAD13}.Publish|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -164,5 +174,6 @@ Global {8CA715D9-6491-42C2-878D-6FBDA9D9B87C} = {D1E4601A-E2A0-43AC-8D33-B05D0001C88F} {1EFE8056-F4BD-4ED0-B7AB-5B61BFE35C29} = {4BEDDC2A-CC7B-4650-BC97-AF81DE36D351} {531643BE-44A4-404B-A3BB-6C44BC7C49D9} = {813A63E0-FB31-48A3-AC0D-D4F3C469706A} + {2D7F07BA-59E0-4B6D-8AB2-5AF9962AAD13} = {D4D520AA-4FE3-4F44-857B-B4AC0AF37E5A} EndGlobalSection EndGlobal diff --git a/autobahn/config/fuzzingclient.json b/autobahn/config/fuzzingclient.json new file mode 100644 index 0000000..48d6cac --- /dev/null +++ b/autobahn/config/fuzzingclient.json @@ -0,0 +1,13 @@ +{ + "options": {"failByDrop": false}, + "outdir": "./reports/servers", + + "servers": [{"agent": "SimpleR", "url": "ws://host.docker.internal:9002"}], + "cases": ["*"], + "exclude-cases": [ + "9.*", + "12.*", + "13.*" + ], + "exclude-agent-cases": {} + } \ No newline at end of file diff --git a/autobahn/fuzzingclient.sh b/autobahn/fuzzingclient.sh new file mode 100755 index 0000000..54d8061 --- /dev/null +++ b/autobahn/fuzzingclient.sh @@ -0,0 +1,3 @@ +#! /bin/sh + +docker run -it --rm -v "${PWD}/config:/config" -v "${PWD}/reports:/reports" -p 9002:9002 --name fuzzingclient crossbario/autobahn-testsuite wstest -m fuzzingclient -s /config/fuzzingclient.json \ No newline at end of file diff --git a/autobahn/server/EchoDispatcher.cs b/autobahn/server/EchoDispatcher.cs new file mode 100644 index 0000000..ed561f0 --- /dev/null +++ b/autobahn/server/EchoDispatcher.cs @@ -0,0 +1,19 @@ +namespace SimpleR.Authobahn.Server; + +public class EchoDispatcher : IWebSocketMessageDispatcher +{ + public Task OnConnectedAsync(IWebsocketConnectionContext connection) + { + return Task.CompletedTask; + } + + public Task OnDisconnectedAsync(IWebsocketConnectionContext connection, Exception? exception) + { + return Task.CompletedTask; + } + + public async Task DispatchMessageAsync(IWebsocketConnectionContext connection, byte[] message) + { + await connection.WriteAsync(message); + } +} \ No newline at end of file diff --git a/autobahn/server/EchoProtocol.cs b/autobahn/server/EchoProtocol.cs new file mode 100644 index 0000000..3d15f59 --- /dev/null +++ b/autobahn/server/EchoProtocol.cs @@ -0,0 +1,17 @@ +using System.Buffers; +using SimpleR.Protocol; + +namespace SimpleR.Authobahn.Server; + +public class EchoProtocol : IDelimitedMessageProtocol +{ + public void WriteMessage(byte[] message, IBufferWriter output) + { + output.Write(message); + } + + public byte[] ParseMessage(ref ReadOnlySequence input) + { + return input.ToArray(); + } +} \ No newline at end of file diff --git a/autobahn/server/Program.cs b/autobahn/server/Program.cs new file mode 100644 index 0000000..feec011 --- /dev/null +++ b/autobahn/server/Program.cs @@ -0,0 +1,20 @@ +using SimpleR.Authobahn.Server; +using SimpleR.Protocol; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +builder.Services.AddSimpleR(); + +var app = builder.Build(); + +app.UseRouting(); + +app.UseAuthorization(); + +app.MapSimpleR("/", b => +{ + b.UseEndOfMessageDelimitedProtocol(new EchoProtocol()).UseDispatcher(); +}); + +app.Run(); diff --git a/autobahn/server/Properties/launchSettings.json b/autobahn/server/Properties/launchSettings.json new file mode 100644 index 0000000..1ebded2 --- /dev/null +++ b/autobahn/server/Properties/launchSettings.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:62410", + "sslPort": 44332 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:9002", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:9003;http://localhost:9002", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/autobahn/server/SimpleR.Authobahn.Server.csproj b/autobahn/server/SimpleR.Authobahn.Server.csproj new file mode 100644 index 0000000..88bb118 --- /dev/null +++ b/autobahn/server/SimpleR.Authobahn.Server.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/autobahn/server/appsettings.Development.json b/autobahn/server/appsettings.Development.json new file mode 100644 index 0000000..33e2405 --- /dev/null +++ b/autobahn/server/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace", + "Microsoft.AspNetCore": "Trace" + } + } +} diff --git a/autobahn/server/appsettings.json b/autobahn/server/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/autobahn/server/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/test/PingPong.Server.Tests/Binary/PingPongCustomBinaryProtocolTests.cs b/test/PingPong.Server.Tests/Binary/PingPongCustomBinaryProtocolTests.cs index 7f94afb..bc62303 100644 --- a/test/PingPong.Server.Tests/Binary/PingPongCustomBinaryProtocolTests.cs +++ b/test/PingPong.Server.Tests/Binary/PingPongCustomBinaryProtocolTests.cs @@ -45,27 +45,4 @@ await socket.SendAsync(new ArraySegment(new byte[] { 5, 0 }), WebSocketMes client.Dispose(); } } - - [Fact] - public async Task SendSinglePartMessage_GetReversed() - { - // Arrange - var receivedQueue = new List(); - var (client, socket) = await _factory.Server.ConnectWebsocketAsync(_route); - try - { - using var sub = client.MessageReceived.Subscribe(message => { receivedQueue.Add(message.Binary); }); - - await socket.SendAsync(new ArraySegment(new byte[] { 1, 2, 3, 4, 5, 0 }), WebSocketMessageType.Binary, - false, CancellationToken.None); - await WaitHelpers.WaitFor(() => receivedQueue.Any()); - - receivedQueue.Should().HaveCount(1); - receivedQueue[0].Should().Equal(5, 4, 3, 2, 1); - } - finally - { - client.Dispose(); - } - } } \ No newline at end of file diff --git a/test/PingPong.Server.Tests/Binary/PingPongDelimitedBinaryProtocolTests.cs b/test/PingPong.Server.Tests/Binary/PingPongDelimitedBinaryProtocolTests.cs index 846bb6a..905d431 100644 --- a/test/PingPong.Server.Tests/Binary/PingPongDelimitedBinaryProtocolTests.cs +++ b/test/PingPong.Server.Tests/Binary/PingPongDelimitedBinaryProtocolTests.cs @@ -66,4 +66,30 @@ await socket.SendAsync(new ArraySegment(new byte[] { 1, 2, 3, 4, 5 }), Web client.Dispose(); } } + + [Fact] + public async Task SendEmptyMessage_GetReversed() + { + // Arrange + var receivedQueue = new List(); + var (client, socket) = await _factory.Server.ConnectWebsocketAsync(_route); + try + { + using var sub = client.MessageReceived.Subscribe((message) => { receivedQueue.Add(message.Binary); }); + + await socket.SendAsync(new ArraySegment([], 0, 0), WebSocketMessageType.Binary, + true, CancellationToken.None); + await socket.SendAsync(new ArraySegment([], 0, 0), WebSocketMessageType.Binary, + true, CancellationToken.None); + await WaitHelpers.WaitFor(() => receivedQueue.Count == 2); + + receivedQueue.Should().HaveCount(2); + receivedQueue[0].Should().Equal([]); + receivedQueue[1].Should().Equal([]); + } + finally + { + client.Dispose(); + } + } } \ No newline at end of file diff --git a/test/PingPong.Server.Tests/Text/PingPongCustomTextProtocolTests.cs b/test/PingPong.Server.Tests/Text/PingPongCustomTextProtocolTests.cs index 8421738..7ce3596 100644 --- a/test/PingPong.Server.Tests/Text/PingPongCustomTextProtocolTests.cs +++ b/test/PingPong.Server.Tests/Text/PingPongCustomTextProtocolTests.cs @@ -72,5 +72,4 @@ await socket.SendAsync(new ArraySegment(bytes), WebSocketMessageType.Text, client.Dispose(); } } - } \ No newline at end of file diff --git a/test/PingPong.Server.Tests/Text/PingPongDelimitedTextProtocolTests.cs b/test/PingPong.Server.Tests/Text/PingPongDelimitedTextProtocolTests.cs index 08952ec..f7435b2 100644 --- a/test/PingPong.Server.Tests/Text/PingPongDelimitedTextProtocolTests.cs +++ b/test/PingPong.Server.Tests/Text/PingPongDelimitedTextProtocolTests.cs @@ -81,4 +81,30 @@ await socket.SendAsync(new ArraySegment(bytes), WebSocketMessageType.Text, client.Dispose(); } } + + [Fact] + public async Task SendEmptyMessage_GetBack() + { + // Arrange + var receivedQueue = new List(); + var (client, socket) = await _factory.Server.ConnectWebsocketAsync(_route); + try + { + using var sub = client.MessageReceived.Subscribe((message) => { receivedQueue.Add(message.Text); }); + await socket.SendAsync(new ArraySegment([], 0, 0), WebSocketMessageType.Text, true, + CancellationToken.None); + await socket.SendAsync(new ArraySegment([], 0, 0), WebSocketMessageType.Text, true, + CancellationToken.None); + + await WaitHelpers.WaitFor(() => receivedQueue.Count == 2); + + receivedQueue.Should().HaveCount(2); + receivedQueue[0].Should().Be(""); + receivedQueue[1].Should().Be(""); + } + finally + { + client.Dispose(); + } + } } \ No newline at end of file diff --git a/test/SimpleR.Protocol.Tests/FrameBufferWriterTests.cs b/test/SimpleR.Protocol.Tests/FrameBufferWriterTests.cs index ab10838..d3f8ae9 100644 --- a/test/SimpleR.Protocol.Tests/FrameBufferWriterTests.cs +++ b/test/SimpleR.Protocol.Tests/FrameBufferWriterTests.cs @@ -17,6 +17,23 @@ public FrameBufferWriterTests() _frameWriter = new FrameBufferWriter(_bufferWriter); } + [Fact] + public void EmptyAdvance_ShouldBeCorrect() + { + // Advance the writer by the number of bytes written + _frameWriter.Advance(0); + + // Finish writing the last frame + _frameWriter.FinishLastFrame(true); + + // Get the written bytes as an array + var result = _bufferWriter.WrittenMemory.ToArray(); + + // Assert that the result is as expected + result.Should() + .BeEquivalentTo(new byte[] { 0, 0, 0, 0, 1 }); + } + [Fact] public void WriteTwoFrames_UsingMemory_ShouldBeCorrect() {