From c02ebee8db6887fc5f5a7d000d0296796a16442c Mon Sep 17 00:00:00 2001 From: = Date: Tue, 31 Aug 2021 03:11:37 +0200 Subject: [PATCH] Propper IPv6 and 4 support with example --- Examples/NetworkTestClient/IPv6Example.cs | 33 +++++++++++++++++++ Examples/NetworkTestClient/Program.cs | 6 +++- Network/Connection.cs | 13 ++++---- Network/ConnectionFactory.cs | 15 +++++---- Network/Network.csproj | 6 ++-- Network/Network.xml | 7 ++-- .../RSA/SecureServerConnectionContainer.cs | 2 +- Network/RSA/SecureTcpConnection.cs | 2 +- Network/RSA/SecureUdpConnection.cs | 4 +-- Network/ServerConnectionContainer.cs | 3 +- Network/TcpConnection.cs | 7 ++-- Network/UdpConnection.cs | 14 +++++--- 12 files changed, 78 insertions(+), 34 deletions(-) create mode 100644 Examples/NetworkTestClient/IPv6Example.cs diff --git a/Examples/NetworkTestClient/IPv6Example.cs b/Examples/NetworkTestClient/IPv6Example.cs new file mode 100644 index 0000000..e4b691d --- /dev/null +++ b/Examples/NetworkTestClient/IPv6Example.cs @@ -0,0 +1,33 @@ +using Network; +using System; +using TestServerClientPackets; + +namespace NetworkTestClient +{ + /// + /// Simple example> + /// 1. Establish a connection + /// 2. Subscribe connectionEstablished event + /// 3. Send and receive a packet + /// + public class IPv6Example + { +#pragma warning disable CS1998 // Bei der asynchronen Methode fehlen "await"-Operatoren. Die Methode wird synchron ausgeführt. + + public async void Demo() +#pragma warning restore CS1998 // Bei der asynchronen Methode fehlen "await"-Operatoren. Die Methode wird synchron ausgeführt. + { + //1. Establish a connection to the server. + ClientConnectionContainer container = ConnectionFactory.CreateClientConnectionContainer("::1", 1234); + //2. Register what happens if we get a connection + container.ConnectionEstablished += async (connection, type) => + { + connection.EnableLogging = true; + Console.WriteLine($"{type.ToString()} Connection established"); + //3. Send a request packet async and directly receive an answer. + CalculationResponse response = await connection.SendAsync(new CalculationRequest(10, 10)); + Console.WriteLine($"Answer received {response.Result}"); + }; + } + } +} \ No newline at end of file diff --git a/Examples/NetworkTestClient/Program.cs b/Examples/NetworkTestClient/Program.cs index bdd5172..28f969e 100644 --- a/Examples/NetworkTestClient/Program.cs +++ b/Examples/NetworkTestClient/Program.cs @@ -18,10 +18,11 @@ public static void Main(string[] args) Console.WriteLine("<6> RawData example"); Console.WriteLine("<7> RSA example"); Console.WriteLine("<8> Stress-Test"); + Console.WriteLine("<9> IPv6 example"); Console.Write("> "); input = 0; - while (!int.TryParse(Console.ReadLine(), out input) || input < 1 || input > 9) + while (!int.TryParse(Console.ReadLine(), out input) || input < 1 || input > 10) Console.Write("> "); switch (input) @@ -55,6 +56,9 @@ public static void Main(string[] args) case 8: new StressTestExample().Demo(); break; + case 9: + new IPv6Example().Demo(); + break; default: throw new ArgumentException(); diff --git a/Network/Connection.cs b/Network/Connection.cs index 79f6912..f30245d 100644 --- a/Network/Connection.cs +++ b/Network/Connection.cs @@ -810,11 +810,11 @@ private void HandleDefaultPackets(Packet packet) } else if (packet.GetType().Equals(typeof(EstablishUdpRequest))) { + IPEndPoint localEndpoint = new IPEndPoint(IPAddress.IPv6Any, GetFreePort()); EstablishUdpRequest establishUdpRequest = (EstablishUdpRequest)packet; - IPEndPoint udpEndPoint = new IPEndPoint(IPAddress.Any, GetFreePort()); - Send(new EstablishUdpResponse(udpEndPoint.Port, establishUdpRequest)); - UdpConnection udpConnection = CreateUdpConnection(udpEndPoint, - new IPEndPoint(IPRemoteEndPoint.Address.MapToIPv4(), establishUdpRequest.UdpPort), true); + Send(new EstablishUdpResponse(localEndpoint.Port, establishUdpRequest)); + UdpConnection udpConnection = CreateUdpConnection(localEndpoint, + new IPEndPoint(IPRemoteEndPoint.Address, establishUdpRequest.UdpPort), true); pendingUDPConnections.Enqueue(udpConnection); connectionEstablished?.Invoke((TcpConnection)this, udpConnection); return; @@ -1008,7 +1008,7 @@ public void Close(CloseReason closeReason, bool callCloseEvent = false) /// The port found. protected int GetFreePort() { - TcpListener tcpListener = new TcpListener(IPAddress.Loopback, 0); + TcpListener tcpListener = new TcpListener(IPAddress.IPv6Loopback, 0); tcpListener.Start(); int port = ((IPEndPoint)tcpListener.LocalEndpoint).Port; tcpListener.Stop(); @@ -1018,12 +1018,11 @@ protected int GetFreePort() /// /// Creates and returns a new , with the given local endpoint, remote endpoint, and write lock state. /// - /// The local that the binds to. /// The remote that the talks to. /// Whether the has a write lock. /// The instantiated . protected virtual UdpConnection CreateUdpConnection(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, bool writeLock) => - new UdpConnection(new UdpClient(localEndPoint), remoteEndPoint, writeLock); + new UdpConnection(localEndPoint, remoteEndPoint, writeLock); #endregion Methods diff --git a/Network/ConnectionFactory.cs b/Network/ConnectionFactory.cs index 85a2991..d85e741 100644 --- a/Network/ConnectionFactory.cs +++ b/Network/ConnectionFactory.cs @@ -1,5 +1,6 @@ using Network.RSA; using System; +using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; @@ -116,9 +117,10 @@ public static TcpConnection CreateSecureTcpConnection(string ipAddress, int port /// public static async Task> CreateTcpConnectionAsync(string ipAddress, int port) { - TcpClient tcpClient = new TcpClient(); + TcpClient tcpClient = new TcpClient(AddressFamily.InterNetworkV6); + tcpClient.Client.DualMode = true; Task timeoutTask = Task.Delay(CONNECTION_TIMEOUT); - Task connectTask = Task.Factory.StartNew(() => tcpClient.Connect(ipAddress, port)); + Task connectTask = tcpClient.ConnectAsync(ipAddress, port); if (await Task.WhenAny(timeoutTask, connectTask).ConfigureAwait(false) != timeoutTask && tcpClient.Connected) return new Tuple(new TcpConnection(tcpClient), ConnectionResult.Connected); @@ -165,9 +167,10 @@ public static async Task> CreateSecureTcp /// public static async Task> CreateSecureTcpConnectionAsync(string ipAddress, int port, RSAPair rsaPair) { - TcpClient tcpClient = new TcpClient(); + TcpClient tcpClient = new TcpClient(AddressFamily.InterNetworkV6); + tcpClient.Client.DualMode = true; Task timeoutTask = Task.Delay(CONNECTION_TIMEOUT); - Task connectTask = Task.Factory.StartNew(() => tcpClient.Connect(ipAddress, port)); + Task connectTask = tcpClient.ConnectAsync(ipAddress, port); if (await Task.WhenAny(timeoutTask, connectTask).ConfigureAwait(false) != timeoutTask && tcpClient.Connected) return new Tuple(new SecureTcpConnection(rsaPair, tcpClient), ConnectionResult.Connected); @@ -281,7 +284,7 @@ public static async Task> CreateUdpConnec cancellationToken.CancelAfter(CONNECTION_TIMEOUT); if (tcpConnection == null || !tcpConnection.IsAlive) return new Tuple(udpConnection, ConnectionResult.TCPConnectionNotAlive); - tcpConnection.EstablishUdpConnection((localEndPoint, RemoteEndPoint) => udpConnection = new UdpConnection(new UdpClient(localEndPoint), RemoteEndPoint)); + tcpConnection.EstablishUdpConnection((localEndpoint, remoteEndpoint) => udpConnection = new UdpConnection(localEndpoint, remoteEndpoint)); while (udpConnection == null && !cancellationToken.IsCancellationRequested) await Task.Delay(25); if (udpConnection == null && cancellationToken.IsCancellationRequested) connectionResult = ConnectionResult.Timeout; return new Tuple(udpConnection, connectionResult); @@ -333,7 +336,7 @@ public static async Task> CreateSecureUdp cancellationToken.CancelAfter(CONNECTION_TIMEOUT); if (tcpConnection == null || !tcpConnection.IsAlive) return new Tuple(udpConnection, ConnectionResult.TCPConnectionNotAlive); - tcpConnection.EstablishUdpConnection((localEndPoint, RemoteEndPoint) => udpConnection = new SecureUdpConnection(new UdpClient(localEndPoint), RemoteEndPoint, rsaPair)); + tcpConnection.EstablishUdpConnection((localEndpoint, remoteEndpoint) => udpConnection = new SecureUdpConnection(localEndpoint, remoteEndpoint, rsaPair)); while (udpConnection == null && !cancellationToken.IsCancellationRequested) await Task.Delay(25); if (udpConnection == null && cancellationToken.IsCancellationRequested) connectionResult = ConnectionResult.Timeout; return new Tuple(udpConnection, connectionResult); diff --git a/Network/Network.csproj b/Network/Network.csproj index 4c6c1ce..7207f2d 100644 --- a/Network/Network.csproj +++ b/Network/Network.csproj @@ -6,7 +6,7 @@ PackageReference true false - 6.2.5.22 + 6.2.5.23 Thomas Christof Indie-Dev Network library supporting: TCP, UDP, RSA, events and objects. Fast and simple, with only 48bit overhead per packet. Send and receive packets with async operations. @@ -27,8 +27,8 @@ Fork me: https://github.com/Toemsel/Network - Removed .NET46 and .NET5 build target - Bluetooth support removed en-US - 6.2.5.22 - 6.2.5.22 + 6.2.5.23 + 6.2.5.23 diff --git a/Network/Network.xml b/Network/Network.xml index c41ed05..7b1a395 100644 --- a/Network/Network.xml +++ b/Network/Network.xml @@ -928,7 +928,6 @@ Creates and returns a new , with the given local endpoint, remote endpoint, and write lock state. - The local that the binds to. The remote that the talks to. Whether the has a write lock. The instantiated . @@ -3371,7 +3370,7 @@ - + Initializes a new instance of the class. @@ -3736,11 +3735,11 @@ Cache of all received bytes. - + Initializes a new instance of the class. - The UDP client to use. + The local end point. The remote end point. Whether the will have a write lock. Whether to skip the call to . diff --git a/Network/RSA/SecureServerConnectionContainer.cs b/Network/RSA/SecureServerConnectionContainer.cs index 77a7391..8533d90 100644 --- a/Network/RSA/SecureServerConnectionContainer.cs +++ b/Network/RSA/SecureServerConnectionContainer.cs @@ -30,7 +30,7 @@ internal SecureServerConnectionContainer(string ipAddress, int port, RSAPair rsa /// The local RSA key-pair. /// Whether to automatically starts to listen to tcp/udp/bluetooth clients. internal SecureServerConnectionContainer(int port, RSAPair rsaPair, bool start = true) - : this(System.Net.IPAddress.Any.ToString(), port, rsaPair, start) { } + : this(System.Net.IPAddress.IPv6Any.ToString(), port, rsaPair, start) { } #endregion Constructors diff --git a/Network/RSA/SecureTcpConnection.cs b/Network/RSA/SecureTcpConnection.cs index 9f6d1de..a0abb77 100644 --- a/Network/RSA/SecureTcpConnection.cs +++ b/Network/RSA/SecureTcpConnection.cs @@ -94,7 +94,7 @@ public override IPacketConverter PacketConverter /// Whether the has a write lock. /// The created . protected override UdpConnection CreateUdpConnection(IPEndPoint localEndPoint, IPEndPoint removeEndPoint, bool writeLock) => - new SecureUdpConnection(new UdpClient(localEndPoint), removeEndPoint, RSAPair, writeLock); + new SecureUdpConnection(localEndPoint, removeEndPoint, RSAPair, writeLock); #endregion Methods } diff --git a/Network/RSA/SecureUdpConnection.cs b/Network/RSA/SecureUdpConnection.cs index 0917d1e..3366217 100644 --- a/Network/RSA/SecureUdpConnection.cs +++ b/Network/RSA/SecureUdpConnection.cs @@ -21,8 +21,8 @@ public class SecureUdpConnection : UdpConnection /// The remote end point to connect to. /// The local RSA key-pair. /// Whether the connection has a write lock. - internal SecureUdpConnection(UdpClient udpClient, IPEndPoint remoteEndPoint, RSAPair rsaPair, bool writeLock = false) - : base(udpClient, remoteEndPoint, writeLock, skipInitializationProcess: true) + internal SecureUdpConnection(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, RSAPair rsaPair, bool writeLock = false) + : base(localEndPoint, remoteEndPoint, writeLock, skipInitializationProcess: true) { //Setup the RSAConnectionHelper object. RSAConnection = new RSAConnection(this, rsaPair); diff --git a/Network/ServerConnectionContainer.cs b/Network/ServerConnectionContainer.cs index 643cd52..cb6c924 100644 --- a/Network/ServerConnectionContainer.cs +++ b/Network/ServerConnectionContainer.cs @@ -66,7 +66,7 @@ internal ServerConnectionContainer(string ipAddress, int port, bool start = true /// The local port. /// Whether to automatically start listening for clients after instantiation. internal ServerConnectionContainer(int port, bool start = true) - : this(System.Net.IPAddress.Any.ToString(), port, start) { } + : this(System.Net.IPAddress.IPv6Any.ToString(), port, start) { } #endregion Constructors @@ -128,6 +128,7 @@ public async Task StartTCPListener() if (IsTCPOnline) return; tcpListener = new TcpListener(System.Net.IPAddress.Parse(IPAddress), Port); + tcpListener.Server.DualMode = true; IsTCPOnline = !IsTCPOnline; tcpListener.Start(); diff --git a/Network/TcpConnection.cs b/Network/TcpConnection.cs index f1c216e..39779a8 100644 --- a/Network/TcpConnection.cs +++ b/Network/TcpConnection.cs @@ -130,15 +130,16 @@ public override bool UseLoopback /// The action to perform upon connection. internal void EstablishUdpConnection(Action connectionEstablished) { - IPEndPoint udpEndPoint = new IPEndPoint(IPAddress.Any, GetFreePort()); + IPEndPoint localEndpoint = new IPEndPoint(IPAddress.IPv6Any, GetFreePort()); + RegisterPacketHandler((packet, connection) => { UnRegisterPacketHandler(this); - connectionEstablished.Invoke(udpEndPoint, new IPEndPoint(IPRemoteEndPoint.Address.MapToIPv4(), packet.UdpPort)); + connectionEstablished.Invoke(localEndpoint, new IPEndPoint(IPRemoteEndPoint.Address, packet.UdpPort)); Send(new EstablishUdpResponseACK()); }, this); - Send(new EstablishUdpRequest(udpEndPoint.Port), this); + Send(new EstablishUdpRequest(localEndpoint.Port), this); } /// diff --git a/Network/UdpConnection.cs b/Network/UdpConnection.cs index c74d6bd..175ed7a 100644 --- a/Network/UdpConnection.cs +++ b/Network/UdpConnection.cs @@ -54,23 +54,27 @@ public class UdpConnection : Connection /// /// Initializes a new instance of the class. /// - /// The UDP client to use. + /// The local end point. /// The remote end point. /// Whether the will have a write lock. /// Whether to skip the call to . - internal UdpConnection(UdpClient udpClient, IPEndPoint remoteEndPoint, bool writeLock = false, bool skipInitializationProcess = false) + internal UdpConnection(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, bool writeLock = false, bool skipInitializationProcess = false) : base() { this.remoteEndPoint = remoteEndPoint; + this.localEndPoint = localEndPoint; - client = udpClient; + client = new UdpClient(AddressFamily.InterNetworkV6); + client.Client.DualMode = true; AcknowledgePending = writeLock; socket = client.Client; - localEndPoint = (IPEndPoint)client.Client.LocalEndPoint; + + client.Client.Bind(localEndPoint); client.Connect(remoteEndPoint); + ObjectMapRefreshed(); - KeepAlive = false; + KeepAlive = true; socket.SendTimeout = -1; socket.ReceiveTimeout = -1;