public void ClientServerDisposeDisconnectsTest()
        {
            IPEndPoint ep = new IPEndPoint(IPAddress.Loopback, 4296);

            bool serverConnected    = false;
            bool serverDisconnected = false;
            bool clientDisconnected = false;

            using (UdpConnectionListener listener = new UdpConnectionListener(new IPEndPoint(IPAddress.Any, 4296)))
                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);
                }
        }
Example #2
0
        public static async Task <QueryResults> QueryAsync(RSAAsymmetricKey key, Target target, TimeSpan timeout)
        {
            if (key == null)
            {
                throw new ArgumentNullException("key");
            }
            if (target == null)
            {
                throw new ArgumentNullException("target");
            }

            var tcs = new TaskCompletionSource <QueryResults>();

            var connection = new UdpClientConnection(GablarskiProtocol.Instance, key);

            connection.Start(MessageTypes.Unreliable);

            var cancelSources = new CancellationTokenSource(timeout);

            cancelSources.Token.Register(() => {
                tcs.TrySetCanceled();
                connection.Dispose();
            });

            connection.ConnectionlessMessageReceived += (sender, args) => {
                var results = args.Message as QueryServerResultMessage;
                if (results == null)
                {
                    return;
                }

                tcs.TrySetResult(new QueryResults(results.ServerInfo, results.Channels, results.Users));

                connection.Dispose();
            };

            await connection.SendConnectionlessMessageAsync(new QueryServerMessage(), target).ConfigureAwait(false);

            return(await tcs.Task.ConfigureAwait(false));
        }
Example #3
0
        /// <summary>
        /// Connect to the specified ip:port endpoint for the matchmaker, then send the specified
        /// message. Returns a task that resolves to a tuple of the established connection and the
        /// first message received from the matchmaker in response to the sent message (usually
        /// the join/host confirmal message). Will throw if the connection closes prematurely or
        /// otherwise errors. Otherwise, the task itself is responsible for disposing of the
        /// connection once the server disconnects.
        /// </summary>
        private static async Task <(UdpClientConnection, MessageReader)> ConnectToMMAndSend(IPAddress address,
                                                                                            ushort port, Action <MessageWriter> writeMessage)
        {
            var firstMessageTask = new TaskCompletionSource <MessageReader>();

            var connection = new UdpClientConnection(new IPEndPoint(address, port));

            connection.KeepAliveInterval    = 1000;
            connection.DisconnectTimeout    = 10000;
            connection.ResendPingMultiplier = 1.2f;

            // Set up an event handler to resolve the task on first non-reselect message received.
            Action <DataReceivedEventArgs> onDataReceived = null;

            onDataReceived = args =>
            {
                try
                {
                    var msg = args.Message.ReadMessage();
                    if (msg.Tag == (byte)MMTags.ReselectServer)
                    {
                        return;                                          // not interested
                    }
                    firstMessageTask.TrySetResult(msg);
                    connection.DataReceived -= onDataReceived;
                }
                finally
                {
                    args.Message.Recycle();
                }
            };
            connection.DataReceived += onDataReceived;

            // Set up an event handler to set an exception for the task on early disconnect.
            connection.Disconnected += (sender, args) =>
            {
                connection.Dispose();
                firstMessageTask.TrySetException(new AUException("Connection to matchmaker prematurely exited"));
            };

            // Connect to the endpoint.
            connection.ConnectAsync(HANDSHAKE);
            await connection.ConnectWaitLock.AsTask();

            // Send the contents.
            connection.SendReliableMessage(writeMessage);

            // Wait for the response to arrive.
            var response = await firstMessageTask.Task;

            // If this is not a redirect, return the result.
            if (response.Tag != (byte)MMTags.Redirect)
            {
                return(connection, response);
            }

            // This is a redirect, so do this again but with the new data.
            var newIp   = response.ReadUInt32();
            var newPort = response.ReadUInt16();

            // Reconnect to new host.
            return(await ConnectToMMAndSend(new IPAddress(newIp), newPort, writeMessage));
        }