예제 #1
0
        /// <summary>
        /// Accept the client and add to our list of connected clients
        /// </summary>
        /// <param name="packet">The BMSByte packet received from connecting client</param>
        /// <param name="steamId">The SteamId of the connecting client</param>
        private void SetupClient(BMSByte packet, SteamId steamId)
        {
            if (Players.Count == MaxConnections)
            {
                // Tell the client why they are being disconnected
                Send(Error.CreateErrorMessage(Time.Timestep, "Max Players Reached On Server", false, MessageGroupIds.MAX_CONNECTIONS, true));

                // Send the close connection frame to the client
                Send(new ConnectionClose(Time.Timestep, false, Receivers.Target, MessageGroupIds.DISCONNECT, false));

                return;
            }
            else if (!AcceptingConnections)
            {
                // Tell the client why they are being disconnected
                Send(Error.CreateErrorMessage(Time.Timestep, "The server is busy and not accepting connections", false, MessageGroupIds.MAX_CONNECTIONS, true));

                // Send the close connection frame to the client
                Send(new ConnectionClose(Time.Timestep, false, Receivers.Target, MessageGroupIds.DISCONNECT, false));

                return;
            }

            // Validate that the connection headers are properly formatted
            byte[] response = Websockets.ValidateConnectionHeader(packet.CompressBytes());

            // The response will be null if the header sent is invalid, if so then disconnect client as they are sending invalid headers
            if (response == null)
            {
                return;
            }

            var player = new FacepunchNetworkingPlayer(ServerPlayerCounter++, steamId, false, this);

            // If all is in order then send the validated response to the client
            Client.Send(response, response.Length, steamId);

            OnPlayerConnected(player);
            steamPlayers.Add(steamId, player);

            // The player has successfully connected
            player.Connected = true;
        }
예제 #2
0
        /// <summary>
        /// Infinite loop listening for new data from all connected clients on a separate thread.
        /// This loop breaks when readThreadCancel is set to true
        /// </summary>
        private void ReadClients()
        {
            SteamId messageFrom = default;

            BMSByte packet = null;

            // Intentional infinite loop
            while (IsBound)
            {
                // If the read has been flagged to be canceled then break from this loop
                if (readThreadCancel)
                {
                    return;
                }

                try
                {
                    packet = Client.Receive(out messageFrom);
                    if (messageFrom == default)
                    {
                        Thread.Sleep(1);
                        continue;
                    }

                    if (packet == null)
                    {
                        Logging.BMSLog.Log("null packet received from non-null player - should not see me!");
                        Thread.Sleep(1);
                        continue;
                    }

                    if (PacketLossSimulation > 0.0f && new Random().NextDouble() <= PacketLossSimulation)
                    {
                        // Skip this message
                        continue;
                    }

                    BandwidthIn += (ulong)packet.Size;
                }
                catch (Exception e)
                {
                    Logging.BMSLog.LogException(e);

                    FacepunchNetworkingPlayer player;
                    if (steamPlayers.TryGetValue(messageFrom, out player))
                    {
                        FinalizeRemovePlayer(player, true);
                    }

                    continue;
                }

                // Check to make sure a message was received
                if (packet == null || packet.Size <= 0)
                {
                    continue;
                }

                if (!steamPlayers.ContainsKey(messageFrom))
                {
                    SetupClient(packet, messageFrom);
                    continue;
                }
                else
                {
                    currentReadingPlayer = steamPlayers[messageFrom];

                    if (!currentReadingPlayer.Accepted && !currentReadingPlayer.PendingAccepted)
                    {
                        // It is possible that the response validation was dropped so
                        // check if the client is resending for a response
                        byte[] response = Websockets.ValidateConnectionHeader(packet.CompressBytes());

                        // The client has sent the connection request again
                        if (response != null)
                        {
                            Client.Send(response, response.Length, messageFrom, P2PSend.Reliable);
                            continue;
                        }
                        else
                        {
                            currentReadingPlayer.PendingAccepted = true;
                            ReadPacket(packet);
                        }
                    }
                    else
                    {
                        // Due to the Forge Networking protocol, the only time that packet 1
                        // will be 71 and the second packet be 69 is a forced disconnect reconnect
                        if (packet[0] == 71 && packet[1] == 69)
                        {
                            Logging.BMSLog.LogFormat("Received packet[0]=71 & packet[1]=69");
                            steamPlayers.Remove(messageFrom);
                            FinalizeRemovePlayer(currentReadingPlayer, true);
                            continue;
                        }

                        currentReadingPlayer.Ping();
                        ReadPacket(packet);
                    }
                }
            }
        }