Esempio n. 1
0
        /// <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&lt;UdpConnection&gt;.</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;
 }
Esempio n. 7
0
 /// <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));
Esempio n. 8
0
        /// <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));
        }
Esempio n. 9
0
 /// <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);
        }
Esempio n. 11
0
 /// <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&lt;UdpConnection&gt;.</returns>
 public List <UdpConnection> this[TcpConnection tcpConnection]
 {
     get { return(connections[tcpConnection]); }
 }
Esempio n. 13
0
        /// <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);
        }
Esempio n. 14
0
 /// <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;
 }
Esempio n. 15
0
 /// <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);
Esempio n. 16
0
 /// <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&lt;UdpConnection&gt;.</returns>
 public List<UdpConnection> this[TcpConnection tcpConnection]
 {
     get { return connections[tcpConnection]; }
 }
Esempio n. 18
0
 /// <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;
 }
Esempio n. 20
0
 /// <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();
 }
Esempio n. 22
0
        /// <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&lt;UdpConnection&gt;.</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));
        }