示例#1
0
        /// <summary>
        /// Create a new client and start sending UDP updates and registering the timeout event.
        /// </summary>
        /// <param name="endPoint">The endpoint of the new client.</param>
        /// <returns>A new net server client instance.</returns>
        private NetServerClient CreateNewClient(IPEndPoint endPoint)
        {
            var netServerClient = new NetServerClient(_udpClient, endPoint);

            netServerClient.UpdateManager.StartUdpUpdates();
            netServerClient.UpdateManager.OnTimeout += () => HandleClientTimeout(netServerClient);

            _clients.Add(netServerClient);

            return(netServerClient);
        }
示例#2
0
        /// <summary>
        /// Handles the event when a client times out. Disconnects the UDP client and cleans up any references
        /// to the client.
        /// </summary>
        /// <param name="client">The client that timed out.</param>
        private void HandleClientTimeout(NetServerClient client)
        {
            var id = client.Id;

            // Only execute the client timeout callback if the client is registered and thus has an ID
            if (client.IsRegistered)
            {
                ClientTimeoutEvent?.Invoke(id);
            }

            client.Disconnect();
            _registeredClients.Remove(id);
            _clients.Remove(client);

            Logger.Get().Info(this, $"Client {id} timed out");
        }
示例#3
0
        /// <summary>
        /// Handle a list of packets from a registered client.
        /// </summary>
        /// <param name="client">The registered client.</param>
        /// <param name="packets">The list of packets to handle.</param>
        private void HandlePacketsRegisteredClient(NetServerClient client, List <Packet.Packet> packets)
        {
            var id = client.Id;

            foreach (var packet in packets)
            {
                // Create a server update packet from the raw packet instance
                var serverUpdatePacket = new ServerUpdatePacket(packet);
                if (!serverUpdatePacket.ReadPacket())
                {
                    // If ReadPacket returns false, we received a malformed packet, which we simply ignore for now
                    continue;
                }

                client.UpdateManager.OnReceivePacket <ServerUpdatePacket, ServerPacketId>(serverUpdatePacket);

                // Let the packet manager handle the received data
                _packetManager.HandleServerPacket(id, serverUpdatePacket);
            }
        }
示例#4
0
        /// <summary>
        /// Handle a list of packets from an unregistered client.
        /// </summary>
        /// <param name="client">The unregistered client.</param>
        /// <param name="packets">The list of packets to handle.</param>
        private void HandlePacketsUnregisteredClient(NetServerClient client, List <Packet.Packet> packets)
        {
            for (var i = 0; i < packets.Count; i++)
            {
                var packet = packets[i];

                // Create a server update packet from the raw packet instance
                var serverUpdatePacket = new ServerUpdatePacket(packet);
                if (!serverUpdatePacket.ReadPacket())
                {
                    // If ReadPacket returns false, we received a malformed packet, which we simply ignore for now
                    // Logger.Get().Warn(this, "Received malformed packet, ignoring");
                    continue;
                }

                client.UpdateManager.OnReceivePacket <ServerUpdatePacket, ServerPacketId>(serverUpdatePacket);

                if (!serverUpdatePacket.GetPacketData().TryGetValue(
                        ServerPacketId.LoginRequest,
                        out var packetData
                        ))
                {
                    continue;
                }

                var loginRequest = (LoginRequest)packetData;

                Logger.Get().Info(this, $"Received login request from '{loginRequest.Username}'");

                // Invoke the handler of the login request and decide what to do with the client based on the result
                var allowClient = LoginRequestEvent?.Invoke(
                    client.Id,
                    client.EndPoint,
                    loginRequest,
                    client.UpdateManager
                    );
                if (!allowClient.HasValue)
                {
                    Logger.Get().Error(this, "Login request has no handler");
                    return;
                }

                if (allowClient.Value)
                {
                    // Logger.Get().Info(this, $"Login request from '{loginRequest.Username}' approved");
                    // client.UpdateManager.SetLoginResponseData(LoginResponseStatus.Success);

                    // Register the client and add them to the dictionary
                    client.IsRegistered           = true;
                    _registeredClients[client.Id] = client;

                    // Now that the client is registered, we forward the rest of the packets to the other handler
                    var leftoverPackets = packets.GetRange(
                        i + 1,
                        packets.Count - i - 1
                        );

                    HandlePacketsRegisteredClient(client, leftoverPackets);
                }
                else
                {
                    client.Disconnect();
                    _clients.Remove(client);
                }

                break;
            }
        }
示例#5
0
        /// <summary>
        /// Callback for when UDP traffic is received.
        /// </summary>
        /// <param name="result">The async result.</param>
        private void OnUdpReceive(IAsyncResult result)
        {
            // Initialize default IPEndPoint for reference in data receive method
            var endPoint = new IPEndPoint(IPAddress.Any, 0);

            byte[] receivedData;
            try {
                receivedData = _udpClient.EndReceive(result, ref endPoint);
            } catch {
                // Logger.Get().Debug(this, $"UDP EndReceive exception: {e.GetType()}, message: {e.Message}");
                // Return if an exception was caught, since there's no need to handle the packets then
                return;
            } finally {
                // Immediately start receiving data again regardless of whether there was an exception or not.
                // But we do this in a loop since it can throw an exception in some cases.
                var tries = 10;
                while (tries > 0)
                {
                    try {
                        _udpClient.BeginReceive(OnUdpReceive, null);
                        break;
                    } catch (Exception e) {
                        Logger.Get().Warn(this, $"UDP BeginReceive exception: {e.GetType()}, message: {e.Message}");
                    }

                    tries--;
                }

                // If we ran out of tries while starting the UDP receive again, we stop the server entirely
                if (tries == 0)
                {
                    Logger.Get().Warn(this, "Could not successfully call BeginReceive, stopping server");
                    Stop();
                }
            }

            List <Packet.Packet> packets;

            // Lock the leftover data array for synchronous data handling
            // This makes sure that from another asynchronous receive callback we don't
            // read/write to it in different places
            lock (_leftoverDataLock) {
                packets = PacketManager.HandleReceivedData(receivedData, ref _leftoverData);
            }

            var             isRegisteredClient = false;
            NetServerClient client             = null;

            // We lock while we are searching for the client that corresponds to this endpoint
            lock (_clientLock) {
                // Figure out which client this data is from or if it is a new client
                foreach (var existingClient in _clients.GetCopy())
                {
                    if (existingClient.HasAddress(endPoint))
                    {
                        isRegisteredClient = existingClient.IsRegistered;
                        client             = existingClient;

                        break;
                    }
                }

                // If an existing client could not be found, we stay in the lock while creating a new client
                if (client == null)
                {
                    Logger.Get().Info(this,
                                      $"Received packet from unknown client with address: {endPoint.Address}:{endPoint.Port}, creating new client");

                    // We didn't find a client with the given address, so we assume it is a new client
                    // that wants to connect
                    client = CreateNewClient(endPoint);
                }
            }

            // Outside of the lock we can handle the packets for the found/created client
            if (isRegisteredClient)
            {
                HandlePacketsRegisteredClient(client, packets);
            }
            else
            {
                HandlePacketsUnregisteredClient(client, packets);
            }
        }