From: Forest Date: Wed, 19 Aug 2020 21:50:55 +0000 (-0700) Subject: Add more tests, fix a bug when recycling unaware hello messages X-Git-Tag: 1.0.0~27^2~5 X-Git-Url: https://git.deb.at/?a=commitdiff_plain;h=1bb325ad879be35098e9a860df697011da58b689;p=rhonda%2Fimpostor.hazel.git Add more tests, fix a bug when recycling unaware hello messages --- diff --git a/Hazel.UnitTests/Hazel.UnitTests.csproj b/Hazel.UnitTests/Hazel.UnitTests.csproj index 45305af..e0d01fb 100644 --- a/Hazel.UnitTests/Hazel.UnitTests.csproj +++ b/Hazel.UnitTests/Hazel.UnitTests.csproj @@ -62,6 +62,7 @@ + diff --git a/Hazel.UnitTests/TestHelper.cs b/Hazel.UnitTests/TestHelper.cs index 0aed2c1..39071c1 100644 --- a/Hazel.UnitTests/TestHelper.cs +++ b/Hazel.UnitTests/TestHelper.cs @@ -5,12 +5,63 @@ using Hazel; using System.Net; using System.Threading; using System.Diagnostics; +using Hazel.Udp.FewerThreads; namespace Hazel.UnitTests { [TestClass] public static class TestHelper { + /// + /// Runs a general test on the given listener and connection. + /// + /// The listener to test. + /// The connection to test. + internal static void RunServerToClientTest(ThreadLimitedUdpConnectionListener listener, Connection connection, int dataSize, SendOption sendOption) + { + //Setup meta stuff + byte[] data = BuildData(dataSize); + ManualResetEvent mutex = new ManualResetEvent(false); + + //Setup listener + listener.NewConnection += delegate (NewConnectionEventArgs ncArgs) + { + ncArgs.Connection.SendBytes(data, sendOption); + }; + + listener.Start(); + + DataReceivedEventArgs? args = null; + //Setup conneciton + connection.DataReceived += delegate (DataReceivedEventArgs a) + { + Trace.WriteLine("Data was received correctly."); + + try + { + args = a; + } + finally + { + mutex.Set(); + } + }; + + connection.Connect(); + + //Wait until data is received + mutex.WaitOne(); + + Assert.AreEqual(data.Length, args.Value.Message.Length); + + for (int i = 0; i < data.Length; i++) + { + Assert.AreEqual(data[i], args.Value.Message.ReadByte()); + } + + Assert.AreEqual(sendOption, args.Value.SendOption); + } + /// /// Runs a general test on the given listener and connection. /// @@ -111,6 +162,57 @@ namespace Hazel.UnitTests Assert.AreEqual(sendOption, result.Value.SendOption); } + + /// + /// Runs a general test on the given listener and connection. + /// + /// The listener to test. + /// The connection to test. + internal static void RunClientToServerTest(ThreadLimitedUdpConnectionListener listener, Connection connection, int dataSize, SendOption sendOption) + { + //Setup meta stuff + byte[] data = BuildData(dataSize); + ManualResetEvent mutex = new ManualResetEvent(false); + ManualResetEvent mutex2 = new ManualResetEvent(false); + + //Setup listener + DataReceivedEventArgs? result = null; + listener.NewConnection += delegate (NewConnectionEventArgs args) + { + args.Connection.DataReceived += delegate (DataReceivedEventArgs innerArgs) + { + Trace.WriteLine("Data was received correctly."); + + result = innerArgs; + + mutex2.Set(); + }; + + mutex.Set(); + }; + + listener.Start(); + + //Connect + connection.Connect(); + + mutex.WaitOne(); + + connection.SendBytes(data, sendOption); + + //Wait until data is received + mutex2.WaitOne(); + + Assert.AreEqual(data.Length, result.Value.Message.Length); + + for (int i = 0; i < data.Length; i++) + { + Assert.AreEqual(data[i], result.Value.Message.ReadByte()); + } + + Assert.AreEqual(sendOption, result.Value.SendOption); + } + /// /// Runs a server disconnect test on the given listener and connection. /// diff --git a/Hazel.UnitTests/ThreadLimitedUdpConnectionTests.cs b/Hazel.UnitTests/ThreadLimitedUdpConnectionTests.cs new file mode 100644 index 0000000..42b7180 --- /dev/null +++ b/Hazel.UnitTests/ThreadLimitedUdpConnectionTests.cs @@ -0,0 +1,505 @@ +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Net; +using System.Threading; +using Hazel.Udp; +using Hazel.Udp.FewerThreads; +using System.Net.Sockets; + +namespace Hazel.UnitTests +{ + [TestClass] + public class ThreadLimitedUdpConnectionTests + { + [TestMethod] + public void ServerDisposeDisconnectsTest() + { + IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 4296); + + bool serverConnected = false; + bool serverDisconnected = false; + bool clientDisconnected = false; + + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(ep)) + { + listener.NewConnection += (evt) => + { + serverConnected = true; + evt.Connection.Disconnected += (o, et) => serverDisconnected = true; + }; + connection.Disconnected += (o, evt) => clientDisconnected = true; + + listener.Start(); + connection.Connect(); + + Thread.Sleep(100); // Gotta wait for the server to set up the events. + listener.Dispose(); + Thread.Sleep(100); + + Assert.IsTrue(serverConnected); + Assert.IsTrue(clientDisconnected); + Assert.IsFalse(serverDisconnected); + } + } + + [TestMethod] + public void ClientServerDisposeDisconnectsTest() + { + IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 4296); + + bool serverConnected = false; + bool serverDisconnected = false; + bool clientDisconnected = false; + + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(ep)) + { + listener.NewConnection += (evt) => + { + serverConnected = true; + evt.Connection.Disconnected += (o, et) => serverDisconnected = true; + }; + + connection.Disconnected += (o, et) => clientDisconnected = true; + + listener.Start(); + connection.Connect(); + + Thread.Sleep(100); // Gotta wait for the server to set up the events. + connection.Dispose(); + + Thread.Sleep(100); + + Assert.IsTrue(serverConnected); + Assert.IsTrue(serverDisconnected); + Assert.IsFalse(clientDisconnected); + } + } + + /// + /// Tests the fields on UdpConnection. + /// + [TestMethod] + public void UdpFieldTest() + { + IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 4296); + + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(ep)) + { + listener.Start(); + + connection.Connect(); + + //Connection fields + Assert.AreEqual(ep, connection.EndPoint); + + //UdpConnection fields + Assert.AreEqual(new IPEndPoint(IPAddress.Loopback, 4296), connection.RemoteEndPoint); + Assert.AreEqual(1, connection.Statistics.DataBytesSent); + Assert.AreEqual(0, connection.Statistics.DataBytesReceived); + } + } + + [TestMethod] + public void UdpHandshakeTest() + { + byte[] TestData = new byte[] { 1, 2, 3, 4, 5, 6 }; + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Loopback, 4296))) + { + listener.Start(); + + MessageReader output = null; + listener.NewConnection += delegate (NewConnectionEventArgs e) + { + output = e.HandshakeData; + }; + + connection.Connect(TestData); + + Thread.Sleep(10); + for (int i = 0; i < TestData.Length; ++i) + { + Assert.AreEqual(TestData[i], output.ReadByte()); + } + } + } + + [TestMethod] + public void UdpUnreliableMessageSendTest() + { + byte[] TestData = new byte[] { 1, 2, 3, 4, 5, 6 }; + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Loopback, 4296))) + { + MessageReader output = null; + listener.NewConnection += delegate (NewConnectionEventArgs e) + { + e.Connection.DataReceived += delegate (DataReceivedEventArgs evt) + { + output = evt.Message; + }; + }; + + listener.Start(); + connection.Connect(); + + for (int i = 0; i < 4; ++i) + { + var msg = MessageWriter.Get(SendOption.None); + msg.Write(TestData); + connection.Send(msg); + msg.Recycle(); + } + + Thread.Sleep(10); + for (int i = 0; i < TestData.Length; ++i) + { + Assert.AreEqual(TestData[i], output.ReadByte()); + } + } + } + + /// + /// Tests IPv4 connectivity. + /// + [TestMethod] + public void UdpIPv4ConnectionTest() + { + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Loopback, 4296))) + { + listener.Start(); + + connection.Connect(); + } + } + + /// + /// Tests IPv4 resilience to multiple hellos. + /// + [TestMethod] + public void ConnectLikeAJerkTest() + { + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) + { + int connects = 0; + listener.NewConnection += (obj) => + { + Interlocked.Increment(ref connects); + obj.HandshakeData.Recycle(); + }; + + listener.Start(); + + socket.Bind(new IPEndPoint(IPAddress.Any, 0)); + var bytes = new byte[2]; + bytes[0] = (byte)UdpSendOption.Hello; + for (int i = 0; i < 10; ++i) + { + socket.SendTo(bytes, new IPEndPoint(IPAddress.Loopback, 4296)); + } + + Thread.Sleep(500); + + Assert.AreEqual(0, listener.ReceiveQueueLength); + Assert.AreEqual(1, connects); + } + } + + /// + /// Tests dual mode connectivity. + /// + [TestMethod] + public void MixedConnectionTest() + { + + using (ThreadLimitedUdpConnectionListener listener2 = new ThreadLimitedUdpConnectionListener(4, new IPEndPoint(IPAddress.IPv6Any, 4296), new ConsoleLogger(), IPMode.IPv6)) + { + listener2.Start(); + + listener2.NewConnection += (evt) => + { + Console.WriteLine($"Connection: {evt.Connection.EndPoint}"); + }; + + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4296))) + { + connection.Connect(); + Assert.AreEqual(ConnectionState.Connected, connection.State); + } + + using (UdpConnection connection2 = new UdpClientConnection(new IPEndPoint(IPAddress.IPv6Loopback, 4296), IPMode.IPv6)) + { + connection2.Connect(); + Assert.AreEqual(ConnectionState.Connected, connection2.State); + } + } + } + + /// + /// Tests dual mode connectivity. + /// + [TestMethod] + public void UdpIPv6ConnectionTest() + { + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger(), IPMode.IPv6)) + { + listener.Start(); + + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4296), IPMode.IPv6)) + { + connection.Connect(); + } + } + } + + /// + /// Tests server to client unreliable communication on the UdpConnection. + /// + [TestMethod] + public void UdpUnreliableServerToClientTest() + { + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Loopback, 4296))) + { + TestHelper.RunServerToClientTest(listener, connection, 10, SendOption.None); + } + } + + /// + /// Tests server to client reliable communication on the UdpConnection. + /// + [TestMethod] + public void UdpReliableServerToClientTest() + { + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Loopback, 4296))) + { + TestHelper.RunServerToClientTest(listener, connection, 10, SendOption.Reliable); + } + } + + /// + /// Tests server to client unreliable communication on the UdpConnection. + /// + [TestMethod] + public void UdpUnreliableClientToServerTest() + { + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Loopback, 4296))) + { + TestHelper.RunClientToServerTest(listener, connection, 10, SendOption.None); + } + } + + /// + /// Tests server to client reliable communication on the UdpConnection. + /// + [TestMethod] + public void UdpReliableClientToServerTest() + { + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Loopback, 4296))) + { + TestHelper.RunClientToServerTest(listener, connection, 10, SendOption.Reliable); + } + } + + /// + /// Tests the keepalive functionality from the client, + /// + [TestMethod] + public void PingDisconnectClientTest() + { +#if DEBUG + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Loopback, 4296))) + { + listener.Start(); + + connection.Connect(); + + // After connecting, quietly stop responding to all messages to fake connection loss. + Thread.Sleep(10); + // listener.TestDropRate = 1; + + connection.KeepAliveInterval = 100; + + Thread.Sleep(1050); //Enough time for ~10 keep alive packets + + Assert.AreEqual(ConnectionState.NotConnected, connection.State); + Assert.AreEqual(3 * connection.MissingPingsUntilDisconnect + 4, connection.Statistics.TotalBytesSent); // + 4 for connecting overhead + } +#else + Assert.Inconclusive("Only works in DEBUG"); +#endif + } + + /// + /// Tests the keepalive functionality from the client, + /// + [TestMethod] + public void KeepAliveClientTest() + { + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Loopback, 4296))) + { + listener.Start(); + + connection.Connect(); + connection.KeepAliveInterval = 100; + + Thread.Sleep(1050); //Enough time for ~10 keep alive packets + + Assert.AreEqual(ConnectionState.Connected, connection.State); + Assert.IsTrue( + connection.Statistics.TotalBytesSent >= 30 && + connection.Statistics.TotalBytesSent <= 50, + "Sent: " + connection.Statistics.TotalBytesSent + ); + } + } + + /// + /// Tests the keepalive functionality from the client, + /// + [TestMethod] + public void KeepAliveServerTest() + { + ManualResetEvent mutex = new ManualResetEvent(false); + + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Loopback, 4296))) + { + UdpConnection client = null; + listener.NewConnection += delegate (NewConnectionEventArgs args) + { + client = (UdpConnection)args.Connection; + client.KeepAliveInterval = 100; + + Thread.Sleep(1050); //Enough time for ~10 keep alive packets + + mutex.Set(); + }; + + listener.Start(); + + connection.Connect(); + + mutex.WaitOne(); + + Assert.AreEqual(ConnectionState.Connected, client.State); + + Assert.IsTrue( + client.Statistics.TotalBytesSent >= 27 && + client.Statistics.TotalBytesSent <= 50, + "Sent: " + client.Statistics.TotalBytesSent + ); + } + } + + /// + /// Tests disconnection from the client. + /// + [TestMethod] + public void ClientDisconnectTest() + { + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Loopback, 4296))) + { + ManualResetEvent mutex = new ManualResetEvent(false); + ManualResetEvent mutex2 = new ManualResetEvent(false); + + listener.NewConnection += delegate (NewConnectionEventArgs args) + { + args.Connection.Disconnected += delegate (object sender2, DisconnectedEventArgs args2) + { + mutex2.Set(); + }; + + mutex.Set(); + }; + + listener.Start(); + + connection.Connect(); + + mutex.WaitOne(); + + connection.Disconnect("Testing"); + + mutex2.WaitOne(); + } + } + + /// + /// Tests disconnection from the server. + /// + [TestMethod] + public void ServerDisconnectTest() + { + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Loopback, 4296))) + { + + ManualResetEvent mutex = new ManualResetEvent(false); + + connection.Disconnected += delegate (object sender, DisconnectedEventArgs args) + { + mutex.Set(); + }; + + listener.NewConnection += delegate (NewConnectionEventArgs args) + { + args.Connection.Disconnect("Testing"); + }; + + listener.Start(); + + connection.Connect(); + + mutex.WaitOne(); + } + } + + /// + /// Tests disconnection from the server. + /// + [TestMethod] + public void ServerExtraDataDisconnectTest() + { + using (ThreadLimitedUdpConnectionListener listener = new ThreadLimitedUdpConnectionListener(2, new IPEndPoint(IPAddress.Any, 4296), new NullLogger())) + using (UdpConnection connection = new UdpClientConnection(new IPEndPoint(IPAddress.Loopback, 4296))) + { + MessageReader received = null; + ManualResetEvent mutex = new ManualResetEvent(false); + + connection.Disconnected += delegate (object sender, DisconnectedEventArgs args) + { + received = args.Message; + mutex.Set(); + }; + + listener.NewConnection += delegate (NewConnectionEventArgs args) + { + MessageWriter writer = MessageWriter.Get(SendOption.None); + writer.Write("Goodbye"); + args.Connection.Disconnect("Testing", writer); + }; + + listener.Start(); + + connection.Connect(); + + mutex.WaitOne(); + + Assert.IsNotNull(received); + Assert.AreEqual("Goodbye", received.ReadString()); + } + } + } +} diff --git a/Hazel.UnitTests/UdpConnectionTestHarness.cs b/Hazel.UnitTests/UdpConnectionTestHarness.cs new file mode 100644 index 0000000..c7cde8d --- /dev/null +++ b/Hazel.UnitTests/UdpConnectionTestHarness.cs @@ -0,0 +1,53 @@ +using Hazel.Udp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Hazel.UnitTests +{ + internal class UdpConnectionTestHarness : UdpConnection + { + public List BytesSent = new List(); + + public override void Connect(byte[] bytes = null, int timeout = 5000) + { + this.State = ConnectionState.Connected; + } + + public override void ConnectAsync(byte[] bytes = null) + { + this.State = ConnectionState.Connected; + } + + protected override bool SendDisconnect(MessageWriter writer) + { + lock (this) + { + if (this.State != ConnectionState.Connected) + { + return false; + } + + this.State = ConnectionState.NotConnected; + } + + return true; + } + + protected override void WriteBytesToConnection(byte[] bytes, int length) + { + this.BytesSent.Add(MessageReader.Get(bytes)); + } + + public void Test_Receive(MessageWriter msg) + { + byte[] buffer = new byte[msg.Length]; + Buffer.BlockCopy(msg.Buffer, 0, buffer, 0, msg.Length); + + var data = MessageReader.Get(buffer); + this.HandleReceive(data, data.Length); + } + } +} diff --git a/Hazel.UnitTests/UdpConnectionTests.cs b/Hazel.UnitTests/UdpConnectionTests.cs index f7a95c0..73017d7 100644 --- a/Hazel.UnitTests/UdpConnectionTests.cs +++ b/Hazel.UnitTests/UdpConnectionTests.cs @@ -3,6 +3,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Net; using System.Threading; using Hazel.Udp; +using System.Net.Sockets; namespace Hazel.UnitTests { @@ -204,6 +205,70 @@ namespace Hazel.UnitTests } } + /// + /// Tests IPv4 resilience to non-hello connections. + /// + [TestMethod] + public void FalseConnectionTest() + { + using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) + using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) + { + int connects = 0; + listener.NewConnection += (obj) => + { + Interlocked.Increment(ref connects); + obj.HandshakeData.Recycle(); + }; + + listener.Start(); + + socket.Bind(new IPEndPoint(IPAddress.Any, 0)); + var bytes = new byte[2]; + bytes[0] = (byte)32; + for (int i = 0; i < 10; ++i) + { + socket.SendTo(bytes, new IPEndPoint(IPAddress.Loopback, 4296)); + } + + Thread.Sleep(500); + + Assert.AreEqual(0, connects); + } + } + + /// + /// Tests IPv4 resilience to multiple hellos. + /// + [TestMethod] + public void ConnectLikeAJerkTest() + { + using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296))) + using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) + { + int connects = 0; + listener.NewConnection += (obj) => + { + Interlocked.Increment(ref connects); + obj.HandshakeData.Recycle(); + }; + + listener.Start(); + + socket.Bind(new IPEndPoint(IPAddress.Any, 0)); + var bytes = new byte[2]; + bytes[0] = (byte)UdpSendOption.Hello; + for (int i = 0; i < 10; ++i) + { + socket.SendTo(bytes, new IPEndPoint(IPAddress.Loopback, 4296)); + } + + Thread.Sleep(500); + + Assert.AreEqual(1, connects); + } + } + /// /// Tests dual mode connectivity. /// diff --git a/Hazel.UnitTests/UdpReliabilityTests.cs b/Hazel.UnitTests/UdpReliabilityTests.cs new file mode 100644 index 0000000..d313cdf --- /dev/null +++ b/Hazel.UnitTests/UdpReliabilityTests.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using Hazel.Udp; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Hazel.UnitTests +{ + [TestClass] + public class UdpReliabilityTests + { + [TestMethod] + public void TestThatAllMessagesAreReceived() + { + List messagesReceived = new List(); + + UdpConnectionTestHarness dut = new UdpConnectionTestHarness(); + dut.DataReceived += evt => + { + messagesReceived.Add(evt.Message); + }; + + MessageWriter data = MessageWriter.Get(SendOption.Reliable); + + for (int i = 1; i < ushort.MaxValue * 2; ++i) + { + // Send a new message, it should be received and ack'd + SetReliableId(data, i); + dut.Test_Receive(data); + + // Resend an old message, it should be ignored + if (i > 2) + { + SetReliableId(data, i - 1); + dut.Test_Receive(data); + + // It should still be ack'd + Assert.AreEqual(2, dut.BytesSent.Count); + dut.BytesSent.RemoveAt(1); + } + + Assert.AreEqual(1, messagesReceived.Count); + messagesReceived.Clear(); + + Assert.AreEqual(1, dut.BytesSent.Count); + dut.BytesSent.Clear(); + } + } + + private static void SetReliableId(MessageWriter data, int i) + { + ushort id = (ushort)i; + data.Buffer[1] = (byte)(id >> 8); + data.Buffer[2] = (byte)id; + } + } +} diff --git a/Hazel/ConnectionListener.cs b/Hazel/ConnectionListener.cs index 3facfe2..aa830c1 100644 --- a/Hazel/ConnectionListener.cs +++ b/Hazel/ConnectionListener.cs @@ -71,7 +71,11 @@ namespace Hazel Action handler = NewConnection; if (handler != null) { - handler(new NewConnectionEventArgs(msg, connection)); + try + { + handler(new NewConnectionEventArgs(msg, connection)); + } + catch { } } else { diff --git a/Hazel/FewerThreads/ThreadLimitedUdpConnectionListener.cs b/Hazel/FewerThreads/ThreadLimitedUdpConnectionListener.cs index df5e000..87e8fbf 100644 --- a/Hazel/FewerThreads/ThreadLimitedUdpConnectionListener.cs +++ b/Hazel/FewerThreads/ThreadLimitedUdpConnectionListener.cs @@ -268,7 +268,7 @@ namespace Hazel.Udp.FewerThreads // Inform the connection of the buffer (new connections need to send an ack back to client) connection.HandleReceive(message, bytesReceived); - if (isHello) + if (isHello && aware) { message.Recycle(); } diff --git a/Hazel/UPnP/ILogger.cs b/Hazel/UPnP/ILogger.cs index 0f89e9c..0bfb2df 100644 --- a/Hazel/UPnP/ILogger.cs +++ b/Hazel/UPnP/ILogger.cs @@ -24,4 +24,17 @@ namespace Hazel { } } + + public class ConsoleLogger : ILogger + { + public void WriteError(string msg) + { + Console.WriteLine($"{DateTime.Now} [ERROR] {msg}"); + } + + public void WriteInfo(string msg) + { + Console.WriteLine($"{DateTime.Now} [INFO] {msg}"); + } + } }