Skip to content

Commit

Permalink
Propper IPv6 and 4 support with example
Browse files Browse the repository at this point in the history
  • Loading branch information
Toemsel committed Aug 31, 2021
1 parent b0b738c commit c02ebee
Show file tree
Hide file tree
Showing 12 changed files with 78 additions and 34 deletions.
33 changes: 33 additions & 0 deletions Examples/NetworkTestClient/IPv6Example.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using Network;
using System;
using TestServerClientPackets;

namespace NetworkTestClient
{
/// <summary>
/// Simple example>
/// 1. Establish a connection
/// 2. Subscribe connectionEstablished event
/// 3. Send and receive a packet
/// </summary>
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<CalculationResponse>(new CalculationRequest(10, 10));
Console.WriteLine($"Answer received {response.Result}");
};
}
}
}
6 changes: 5 additions & 1 deletion Examples/NetworkTestClient/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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();
Expand Down
13 changes: 6 additions & 7 deletions Network/Connection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1008,7 +1008,7 @@ public void Close(CloseReason closeReason, bool callCloseEvent = false)
/// <returns>The port found.</returns>
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();
Expand All @@ -1018,12 +1018,11 @@ protected int GetFreePort()
/// <summary>
/// Creates and returns a new <see cref="UdpConnection"/>, with the given local endpoint, remote endpoint, and write lock state.
/// </summary>
/// <param name="localEndPoint">The local <see cref="IPEndPoint"/> that the <see cref="UdpConnection"/> binds to.</param>
/// <param name="remoteEndPoint">The remote <see cref="IPEndPoint"/> that the <see cref="UdpConnection"/> talks to.</param>
/// <param name="writeLock">Whether the <see cref="UdpConnection"/> has a write lock.</param>
/// <returns>The instantiated <see cref="UdpConnection"/>.</returns>
protected virtual UdpConnection CreateUdpConnection(IPEndPoint localEndPoint, IPEndPoint remoteEndPoint, bool writeLock) =>
new UdpConnection(new UdpClient(localEndPoint), remoteEndPoint, writeLock);
new UdpConnection(localEndPoint, remoteEndPoint, writeLock);

#endregion Methods

Expand Down
15 changes: 9 additions & 6 deletions Network/ConnectionFactory.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Network.RSA;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -116,9 +117,10 @@ public static TcpConnection CreateSecureTcpConnection(string ipAddress, int port
/// </returns>
public static async Task<Tuple<TcpConnection, ConnectionResult>> 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<TcpConnection, ConnectionResult>(new TcpConnection(tcpClient), ConnectionResult.Connected);

Expand Down Expand Up @@ -165,9 +167,10 @@ public static async Task<Tuple<TcpConnection, ConnectionResult>> CreateSecureTcp
/// </returns>
public static async Task<Tuple<TcpConnection, ConnectionResult>> 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<TcpConnection, ConnectionResult>(new SecureTcpConnection(rsaPair, tcpClient), ConnectionResult.Connected);

Expand Down Expand Up @@ -281,7 +284,7 @@ public static async Task<Tuple<UdpConnection, ConnectionResult>> CreateUdpConnec
cancellationToken.CancelAfter(CONNECTION_TIMEOUT);
if (tcpConnection == null || !tcpConnection.IsAlive)
return new Tuple<UdpConnection, ConnectionResult>(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>(udpConnection, connectionResult);
Expand Down Expand Up @@ -333,7 +336,7 @@ public static async Task<Tuple<UdpConnection, ConnectionResult>> CreateSecureUdp
cancellationToken.CancelAfter(CONNECTION_TIMEOUT);
if (tcpConnection == null || !tcpConnection.IsAlive)
return new Tuple<UdpConnection, ConnectionResult>(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>(udpConnection, connectionResult);
Expand Down
6 changes: 3 additions & 3 deletions Network/Network.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<Version>6.2.5.22</Version>
<Version>6.2.5.23</Version>
<Authors>Thomas Christof</Authors>
<Company>Indie-Dev</Company>
<Description>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.
Expand All @@ -27,8 +27,8 @@ Fork me: https://github.com/Toemsel/Network</Description>
- Removed .NET46 and .NET5 build target
- Bluetooth support removed</PackageReleaseNotes>
<NeutralLanguage>en-US</NeutralLanguage>
<AssemblyVersion>6.2.5.22</AssemblyVersion>
<FileVersion>6.2.5.22</FileVersion>
<AssemblyVersion>6.2.5.23</AssemblyVersion>
<FileVersion>6.2.5.23</FileVersion>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|netstandard2.0|AnyCPU'">
Expand Down
7 changes: 3 additions & 4 deletions Network/Network.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Network/RSA/SecureServerConnectionContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ internal SecureServerConnectionContainer(string ipAddress, int port, RSAPair rsa
/// <param name="rsaPair">The local RSA key-pair.</param>
/// <param name="start">Whether to automatically starts to listen to tcp/udp/bluetooth clients.</param>
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

Expand Down
2 changes: 1 addition & 1 deletion Network/RSA/SecureTcpConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public override IPacketConverter PacketConverter
/// <param name="writeLock">Whether the <see cref="SecureUdpConnection"/> has a write lock.</param>
/// <returns>The created <see cref="SecureUdpConnection"/>.</returns>
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
}
Expand Down
4 changes: 2 additions & 2 deletions Network/RSA/SecureUdpConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ public class SecureUdpConnection : UdpConnection
/// <param name="remoteEndPoint">The remote end point to connect to.</param>
/// <param name="rsaPair">The local RSA key-pair.</param>
/// <param name="writeLock">Whether the connection has a write lock.</param>
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);
Expand Down
3 changes: 2 additions & 1 deletion Network/ServerConnectionContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ internal ServerConnectionContainer(string ipAddress, int port, bool start = true
/// <param name="port">The local port.</param>
/// <param name="start">Whether to automatically start listening for clients after instantiation.</param>
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

Expand Down Expand Up @@ -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();

Expand Down
7 changes: 4 additions & 3 deletions Network/TcpConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,16 @@ public override bool UseLoopback
/// <param name="connectionEstablished">The action to perform upon connection.</param>
internal void EstablishUdpConnection(Action<IPEndPoint, IPEndPoint> connectionEstablished)
{
IPEndPoint udpEndPoint = new IPEndPoint(IPAddress.Any, GetFreePort());
IPEndPoint localEndpoint = new IPEndPoint(IPAddress.IPv6Any, GetFreePort());

RegisterPacketHandler<EstablishUdpResponse>((packet, connection) =>
{
UnRegisterPacketHandler<EstablishUdpResponse>(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);
}

/// <inheritdoc />
Expand Down
14 changes: 9 additions & 5 deletions Network/UdpConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,27 @@ public class UdpConnection : Connection
/// <summary>
/// Initializes a new instance of the <see cref="UdpConnection"/> class.
/// </summary>
/// <param name="udpClient">The UDP client to use.</param>
/// <param name="localEndPoint">The local end point.</param>
/// <param name="remoteEndPoint">The remote end point.</param>
/// <param name="writeLock">Whether the <see cref="UdpConnection"/> will have a write lock.</param>
/// <param name="skipInitializationProcess">Whether to skip the call to <see cref="Connection.Init()"/>.</param>
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;

Expand Down

0 comments on commit c02ebee

Please sign in to comment.