/// <summary> /// Handles when a <see cref="UdpConnection"/> successfully connects to the server. /// </summary> /// <param name="tcpConnection">The parent <see cref="TcpConnection"/>.</param> /// <param name="udpConnection">The connected <see cref="UdpConnection"/>.</param> private void udpConnectionReceived(TcpConnection tcpConnection, UdpConnection udpConnection) { if (!AllowUDPConnections || this[tcpConnection].Count >= UDPConnectionLimit) { CloseReason closeReason = (this[tcpConnection].Count >= UDPConnectionLimit) ? CloseReason.UdpLimitExceeded : CloseReason.InvalidUdpRequest; tcpConnection.Close(closeReason, true); return; } this[tcpConnection].Add(udpConnection); udpConnection.NetworkConnectionClosed += connectionClosed; KnownTypes.ForEach(udpConnection.AddExternalPackets); //Inform all subscribers. if (connectionEstablished != null && connectionEstablished.GetInvocationList().Length > 0) { connectionEstablished(udpConnection, ConnectionType.UDP); } }
/// <summary> /// TCPs the or UDP connection closed. /// </summary> /// <param name="closeReason">The close reason.</param> /// <param name="connection">The connection.</param> private void connectionClosed(CloseReason closeReason, Connection connection) { if (connection.GetType().Equals(typeof(TcpConnection))) { List <UdpConnection> udpConnections = new List <UdpConnection>(); TcpConnection tcpConnection = (TcpConnection)connection; while (!connections.TryRemove(tcpConnection, out udpConnections)) { Thread.Sleep(new Random().Next(0, 8)); //If we could not remove the tcpConnection, try it again. } udpConnections.ForEach(u => u.ExternalClose(closeReason)); } else if (connection.GetType().Equals(typeof(UdpConnection))) { TcpConnection tcpConnection = this[(UdpConnection)connection]; if (tcpConnection == null) { return; //UDP connection already removed } //because the TCP connection is already dead. connections[tcpConnection].Remove((UdpConnection)connection); } if (connectionLost != null && connectionLost.GetInvocationList().Length > 0 && connection.GetType().Equals(typeof(TcpConnection))) { connectionLost(connection, ConnectionType.TCP, closeReason); } else if (connectionLost != null && connectionLost.GetInvocationList().Length > 0 && connection.GetType().Equals(typeof(UdpConnection))) { connectionLost(connection, ConnectionType.UDP, closeReason); } }
/// <summary> /// Starts a TCP server and listens for incoming <see cref="TcpConnection"/>s. /// </summary> public async Task StartTCPListener() { if (IsTCPOnline) { return; } tcpListener = new TcpListener(System.Net.IPAddress.Parse(IPAddress), Port); tcpListener.Server.DualMode = true; IsTCPOnline = !IsTCPOnline; tcpListener.Start(); try { while (IsTCPOnline) { TcpClient tcpClient = await tcpListener.AcceptTcpClientAsync(); TcpConnection tcpConnection = CreateTcpConnection(tcpClient); tcpConnection.NetworkConnectionClosed += connectionClosed; tcpConnection.ConnectionEstablished += udpConnectionReceived; connections.GetOrAdd(tcpConnection, new List <UdpConnection>()); //Inform all subscribers. if (connectionEstablished != null && connectionEstablished.GetInvocationList().Length > 0) { connectionEstablished(tcpConnection, ConnectionType.TCP); } KnownTypes.ForEach(tcpConnection.AddExternalPackets); } } //The TCP-Listener has been shut down. catch (ObjectDisposedException) { } }
/// <summary> /// Creates a new instance of a connection container. /// </summary> /// <param name="tcpConnection">The TCP connection.</param> /// <param name="udpConnection">The UDP connection.</param> /// <returns>ConnectionContainer.</returns> /// <exception cref="System.ArgumentException">TCP and UDP connection must be connected to an endpoint.</exception> public static ClientConnectionContainer CreateClientConnectionContainer(TcpConnection tcpConnection, UdpConnection udpConnection) { if (tcpConnection == null ||!tcpConnection.IsAlive) throw new ArgumentException("TCP connection must be connected to an endpoint."); return new ClientConnectionContainer(tcpConnection, udpConnection); }
/// <summary> /// Creates a new instance of a udp connection async. /// </summary> /// <param name="tcpConnection">The tcp connection to establish the udp connection.</param> /// <returns>Task<UdpConnection>.</returns> /// <exception cref="ArgumentException">TcpConnection is not connected to the endpoint.</exception> public static async Task<Tuple<UdpConnection, ConnectionResult>> CreateUdpConnectionAsync(TcpConnection tcpConnection) { UdpConnection udpConnection = null; ConnectionResult connectionResult = ConnectionResult.Connected; CancellationTokenSource cancellationToken = new CancellationTokenSource(); cancellationToken.CancelAfter(CONNECTION_TIMEOUT); if (tcpConnection == null || !tcpConnection.IsAlive) throw new ArgumentException("TcpConnection is not connected to the endpoint."); tcpConnection.EstablishUdpConnection((localEndPoint, RemoteEndPoint) => udpConnection = new UdpConnection(new UdpClient(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); }
/// <summary> /// Creates a new instance of a udp connection. /// </summary> /// <param name="tcpConnection">The tcp connection to establish the udp connection.</param> /// <returns>The UdpConnection.</returns> public static UdpConnection CreateUdpConnection(TcpConnection tcpConnection, out ConnectionResult connectionResult) { Tuple<UdpConnection, ConnectionResult> connectionRequest = CreateUdpConnectionAsync(tcpConnection).Result; connectionResult = connectionRequest.Item2; return connectionRequest.Item1; }
/// <summary> /// Creates a <see cref="SecureClientConnectionContainer"/> with the given <see cref="TcpConnection"/> and <see cref="UdpConnection"/>. /// </summary> /// <param name="tcpConnection">The <see cref="TcpConnection"/> to use.</param> /// <param name="udpConnection">The <see cref="UdpConnection"/> to use.</param> /// <param name="publicKey">The public RSA key in xml format. (https://superdry.apphb.com/tools/online-rsa-key-converter)</param> /// <param name="privateKey">The private RSA key in xml format. (https://superdry.apphb.com/tools/online-rsa-key-converter)</param> /// <param name="keySize">The size of the RSA keys.</param> /// <returns>The created <see cref="SecureClientConnectionContainer"/>.</returns> /// <exception cref="ArgumentException">Thrown if the given <see cref="TcpConnection"/> is not connected.</exception> public static ClientConnectionContainer CreateSecureClientConnectionContainer(TcpConnection tcpConnection, UdpConnection udpConnection, string publicKey, string privateKey, int keySize = 2048) => CreateSecureClientConnectionContainer(tcpConnection, udpConnection, new RSAPair(publicKey, privateKey, keySize));
/// <summary> /// Asynchronously creates a <see cref="SecureUdpConnection"/> with the given parent <see cref="TcpConnection"/>. /// </summary> /// <param name="tcpConnection">The <see cref="TcpConnection"/> via which to connect the <see cref="SecureUdpConnection"/>.</param> /// <param name="rsaPair">The RSA key-pair to use.</param> /// <returns> /// A <see cref="Task"/> representing the asynchronous operation with the promise of a tuple holding the created /// <see cref="SecureUdpConnection"/> and <see cref="ConnectionResult"/> on completion. /// </returns> /// <exception cref="ArgumentException">The given <see cref="TcpConnection"/> isn't connected.</exception> public static async Task <Tuple <UdpConnection, ConnectionResult> > CreateSecureUdpConnectionAsync(TcpConnection tcpConnection, RSAPair rsaPair) { UdpConnection udpConnection = null; ConnectionResult connectionResult = ConnectionResult.Connected; CancellationTokenSource cancellationToken = new CancellationTokenSource(); 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)); while (udpConnection == null && !cancellationToken.IsCancellationRequested) { await Task.Delay(25); } if (udpConnection == null && cancellationToken.IsCancellationRequested) { connectionResult = ConnectionResult.Timeout; } return(new Tuple <UdpConnection, ConnectionResult>(udpConnection, connectionResult)); }
/// <summary> /// Asynchronously creates a <see cref="SecureUdpConnection"/> with the given parent <see cref="TcpConnection"/>. /// </summary> /// <param name="tcpConnection">The <see cref="TcpConnection"/> via which to connect the <see cref="SecureUdpConnection"/>.</param> /// <param name="keySize">The size of the RSA keys.</param> /// <returns> /// A <see cref="Task"/> representing the asynchronous operation with the promise of a tuple holding the created /// <see cref="SecureUdpConnection"/> and <see cref="ConnectionResult"/> on completion. /// </returns> /// <exception cref="ArgumentException">The given <see cref="TcpConnection"/> isn't connected.</exception> public static async Task <Tuple <UdpConnection, ConnectionResult> > CreateSecureUdpConnectionAsync(TcpConnection tcpConnection, int keySize = 2048) => await CreateSecureUdpConnectionAsync(tcpConnection, RSAKeyGeneration.Generate(keySize));
/// <summary> /// A UDP connection has been established. /// </summary> /// <param name="arg1">The arg1.</param> /// <param name="arg2">The arg2.</param> /// <exception cref="NotImplementedException"></exception> private void udpConnectionReceived(TcpConnection tcpConnection, UdpConnection udpConnection) { if (!AllowUDPConnections || this[tcpConnection].Count >= UDPConnectionLimit) { CloseReason closeReason = (this[tcpConnection].Count >= UDPConnectionLimit) ? CloseReason.UdpLimitExceeded : CloseReason.InvalidUdpRequest; tcpConnection.Close(closeReason); tcpOrUdpConnectionClosed(closeReason, tcpConnection); return; } this[tcpConnection].Add(udpConnection); udpConnection.ConnectionClosed += tcpOrUdpConnectionClosed; //Inform all subscribers. if (connectionEstablished != null && connectionEstablished.GetInvocationList().Length > 0) connectionEstablished(udpConnection, ConnectionType.UDP); }
/// <summary> /// Creates a new instance of a secure-connection container. (RSA Encryption) /// </summary> /// <param name="tcpConnection">The TCP connection.</param> /// <param name="udpConnection">The UDP connection.</param> /// <param name="keySize">The keySize.</param> /// <returns>ConnectionContainer.</returns> /// <exception cref="System.ArgumentException">TCP and UDP connection must be connected to an endpoint.</exception> public static ClientConnectionContainer CreateSecureClientConnectionContainer(TcpConnection tcpConnection, UdpConnection udpConnection, int keySize = 2048, bool UseUDP = false) => CreateSecureClientConnectionContainer(tcpConnection, udpConnection, RSAKeyGeneration.Generate(keySize), UseUDP);
/// <summary> /// Gets the <see cref="List{UdpConnection}"/> with the specified TCP connection. /// </summary> /// <param name="tcpConnection">The TCP connection.</param> /// <returns>List<UdpConnection>.</returns> public List <UdpConnection> this[TcpConnection tcpConnection] { get { return(connections[tcpConnection]); } }
/// <summary> /// Opens the new TCP connection and applies the already registered packet handlers. /// </summary> private async Task OpenNewTCPConnection() { Tuple <TcpConnection, ConnectionResult> result = await CreateTcpConnection(); if (result.Item2 != ConnectionResult.Connected) { Reconnect(); return; } tcpConnection = result.Item1; //Restore old state by adding old packets tcpConnection.RestorePacketHandler(tcpPacketHandlerBackup); //Restore new state by adding packets the user wanted to register while the connection was dead. tcpPacketHandlerBuffer.ForEach(t => { MethodInfo registerPacketHandler = typeof(Connection).GetMethod("RegisterPacketHandler", BindingFlags.NonPublic | BindingFlags.Instance); registerPacketHandler = registerPacketHandler.MakeGenericMethod(t.Item1); registerPacketHandler.Invoke(tcpConnection, new object[] { t.Item2, t.Item3 }); }); tcpStaticPacketHandlerBuffer.ForEach(t => { MethodInfo registerPacketHandler = typeof(Connection).GetMethod("RegisterStaticPacketHandler", BindingFlags.NonPublic | BindingFlags.Instance); registerPacketHandler = registerPacketHandler.MakeGenericMethod(t.Item1); registerPacketHandler.Invoke(tcpConnection, new object[] { t.Item2 }); }); tcpConnection.ConnectionClosed += (c, cc) => { tcpPacketHandlerBackup = cc.ObjectMapper; connectionLost?.Invoke(tcpConnection, ConnectionType.TCP, c); Reconnect(); }; sendSlowBuffer.ForEach(tcpConnection.Send); sendSlowObjectBuffer.ForEach(p => tcpConnection.Send(p.Item1, p.Item2)); //Restore new state by removing the packets the user wanted to unregister while the connection was dead. tcpUnPacketHandlerBuffer.ForEach(t => { MethodInfo unRegisterPacketHandler = typeof(Connection).GetMethod("UnRegisterPacketHandler"); unRegisterPacketHandler = unRegisterPacketHandler.MakeGenericMethod(t.Item1); unRegisterPacketHandler.Invoke(tcpConnection, new object[] { t.Item2 }); }); tcpStaticUnPacketHandlerBuffer.ForEach(t => { MethodInfo unRegisterPacketHandler = typeof(Connection).GetMethod("UnRegisterStaticPacketHandler"); unRegisterPacketHandler = unRegisterPacketHandler.MakeGenericMethod(t); unRegisterPacketHandler.Invoke(tcpConnection, null); }); KnownTypes.ForEach(TcpConnection.AddExternalPackets); //Clear the buffers since we added and removed the packet types. sendSlowBuffer.Clear(); sendSlowObjectBuffer.Clear(); tcpPacketHandlerBuffer.Clear(); tcpUnPacketHandlerBuffer.Clear(); tcpStaticPacketHandlerBuffer.Clear(); tcpStaticUnPacketHandlerBuffer.Clear(); if (!tcpConnection.IsAlive) { return; //Connection could already be dead because of the prePackets. } connectionEstablished?.Invoke(tcpConnection, ConnectionType.TCP); }
/// <summary> /// Initializes a new instance of the <see cref="ClientConnectionContainer"/> class. /// </summary> /// <param name="tcpConnection">The TCP connection.</param> /// <param name="udpConnection">The UDP connection.</param> internal ClientConnectionContainer(TcpConnection tcpConnection, UdpConnection udpConnection) : base(tcpConnection.IPRemoteEndPoint.Address.ToString(), tcpConnection.IPRemoteEndPoint.Port) { this.tcpConnection = tcpConnection; this.udpConnection = udpConnection; }
/// <summary> /// Creates a <see cref="SecureUdpConnection"/> with the given parent <see cref="TcpConnection"/>. /// </summary> /// <param name="tcpConnection">The <see cref="TcpConnection"/> via which to connect the <see cref="SecureUdpConnection"/>.</param> /// <param name="connectionResult">The connection result.</param> /// <param name="keySize">The size of the RSA keys.</param> /// <returns>The created <see cref="SecureUdpConnection"/>.</returns> public static UdpConnection CreateSecureUdpConnection(TcpConnection tcpConnection, out ConnectionResult connectionResult, int keySize = 2048) => CreateSecureUdpConnection(tcpConnection, RSAKeyGeneration.Generate(keySize), out connectionResult);
/// <summary> /// Creates a <see cref="SecureUdpConnection"/> with the given parent <see cref="TcpConnection"/>. /// </summary> /// <param name="tcpConnection">The <see cref="TcpConnection"/> via which to connect the <see cref="SecureUdpConnection"/>.</param> /// <param name="publicKey">The public RSA key in xml format. (https://superdry.apphb.com/tools/online-rsa-key-converter)</param> /// <param name="privateKey">The private RSA key in xml format. (https://superdry.apphb.com/tools/online-rsa-key-converter)</param> /// <param name="connectionResult">The connection result.</param> /// <param name="keySize">The size of the RSA keys.</param> /// <returns>The created <see cref="SecureUdpConnection"/>.</returns> public static UdpConnection CreateSecureUdpConnection(TcpConnection tcpConnection, string publicKey, string privateKey, out ConnectionResult connectionResult, int keySize = 2048) => CreateSecureUdpConnection(tcpConnection, new RSAPair(publicKey, privateKey, keySize), out connectionResult);
/// <summary> /// Gets the <see cref="List{UdpConnection}"/> with the specified TCP connection. /// </summary> /// <param name="tcpConnection">The TCP connection.</param> /// <returns>List<UdpConnection>.</returns> public List<UdpConnection> this[TcpConnection tcpConnection] { get { return connections[tcpConnection]; } }
/// <summary> /// Asynchronously creates a <see cref="SecureUdpConnection"/> with the given parent <see cref="TcpConnection"/>. /// </summary> /// <param name="tcpConnection">The <see cref="TcpConnection"/> via which to connect the <see cref="SecureUdpConnection"/>.</param> /// <param name="publicKey">The public RSA key in xml format. (https://superdry.apphb.com/tools/online-rsa-key-converter)</param> /// <param name="privateKey">The private RSA key in xml format. (https://superdry.apphb.com/tools/online-rsa-key-converter)</param> /// <param name="keySize">The size of the RSA keys.</param> /// <returns> /// A <see cref="Task"/> representing the asynchronous operation with the promise of a tuple holding the created /// <see cref="SecureUdpConnection"/> and <see cref="ConnectionResult"/> on completion. /// </returns> /// <exception cref="ArgumentException">The given <see cref="TcpConnection"/> isn't connected.</exception> public static async Task <Tuple <UdpConnection, ConnectionResult> > CreateSecureUdpConnectionAsync(TcpConnection tcpConnection, string publicKey, string privateKey, int keySize = 2048) => await CreateSecureUdpConnectionAsync(tcpConnection, new RSAPair(publicKey, privateKey, keySize));
/// <summary> /// Opens the new TCP connection and applies the already registered packet handlers. /// </summary> private async Task<bool> OpenNewTCPConnection() { Tuple<TcpConnection, ConnectionResult> result = await ConnectionFactory.CreateTcpConnectionAsync(IPAddress, Port); if (result.Item2 != ConnectionResult.Connected) { Reconnect(); return false; } tcpConnection = result.Item1; tcpPacketHandlerBuffer.ForEach(t => tcpConnection.RegisterPacketHandler(t.Item1, t.Item2)); tcpConnection.ConnectionClosed += (c, cc) => { Reconnect(); connectionLost?.Invoke(tcpConnection, ConnectionType.TCP, c); }; sendSlowBuffer.ForEach(tcpConnection.Send); connectionEstablished?.Invoke(tcpConnection, ConnectionType.TCP); return true; }
/// <summary> /// Creates a <see cref="SecureClientConnectionContainer"/> with the given <see cref="TcpConnection"/> and <see cref="UdpConnection"/>. /// </summary> /// <param name="tcpConnection">The <see cref="TcpConnection"/> to use.</param> /// <param name="udpConnection">The <see cref="UdpConnection"/> to use.</param> /// <param name="keySize">The size of the RSA keys.</param> /// <returns>The created <see cref="SecureClientConnectionContainer"/>.</returns> /// <exception cref="ArgumentException">Thrown if the given <see cref="TcpConnection"/> is not connected.</exception> public static ClientConnectionContainer CreateSecureClientConnectionContainer(TcpConnection tcpConnection, UdpConnection udpConnection, int keySize = 2048) => CreateSecureClientConnectionContainer(tcpConnection, udpConnection, RSAKeyGeneration.Generate(keySize));
/// <summary> /// Initializes a new instance of the <see cref="ClientConnectionContainer"/> class. /// </summary> /// <param name="tcpConnection">The TCP connection.</param> /// <param name="udpConnection">The UDP connection.</param> internal ClientConnectionContainer(TcpConnection tcpConnection, UdpConnection udpConnection) : base(tcpConnection.IPRemoteEndPoint.Address.ToString(), tcpConnection.IPRemoteEndPoint.Port) { this.tcpConnection = tcpConnection; this.udpConnection = udpConnection; TryConnect(); }
/// <summary> /// Creates a <see cref="SecureClientConnectionContainer"/> with the given <see cref="TcpConnection"/> and <see cref="UdpConnection"/>. /// </summary> /// <param name="tcpConnection">The <see cref="TcpConnection"/> to use.</param> /// <param name="udpConnection">The <see cref="UdpConnection"/> to use.</param> /// <param name="rsaPair">The RSA key-pair to use.</param> /// <returns>The created <see cref="SecureClientConnectionContainer"/>.</returns> /// <exception cref="ArgumentException">Thrown if the given <see cref="TcpConnection"/> is not connected.</exception> public static ClientConnectionContainer CreateSecureClientConnectionContainer(TcpConnection tcpConnection, UdpConnection udpConnection, RSAPair rsaPair) { if (tcpConnection == null || !tcpConnection.IsAlive) { throw new ArgumentException("TCP connection must be connected to an endpoint."); } var secureClientConnectionContainer = new SecureClientConnectionContainer(tcpConnection, udpConnection, rsaPair); secureClientConnectionContainer.Initialize(); return(secureClientConnectionContainer); }
/// <summary> /// Creates a new instance of a udp connection async. /// </summary> /// <param name="tcpConnection">The tcp connection to establish the udp connection.</param> /// <returns>Task<UdpConnection>.</returns> /// <exception cref="ArgumentException">TcpConnection is not connected to the endpoint.</exception> public static async Task <Tuple <UdpConnection, ConnectionResult> > CreateUdpConnectionAsync(TcpConnection tcpConnection) { UdpConnection udpConnection = null; ConnectionResult connectionResult = ConnectionResult.Connected; CancellationTokenSource cancellationToken = new CancellationTokenSource(); cancellationToken.CancelAfter(CONNECTION_TIMEOUT); if (tcpConnection == null || !tcpConnection.IsAlive) { throw new ArgumentException("TcpConnection is not connected to the endpoint."); } tcpConnection.EstablishUdpConnection((localEndPoint, RemoteEndPoint) => udpConnection = new UdpConnection(new UdpClient(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)); }