protected void InitializeMasterClient(string host, ushort port)
        {
            // Get a client stream for reading and writing.
            // Stream stream = client.GetStream();

            //获取需要用于验证服务器连接的随机哈希键
            // Get a random hash key that needs to be used for validating that the server was connected to
            headerHash = Websockets.HeaderHashKey();

            //这是一个典型的Websockets接受头被验证
            // This is a typical Websockets accept header to be validated
            byte[] connectHeader = Websockets.ConnectionHeader(headerHash, port);

            //将接受标头发送到服务器进行验证
            // Send the accept headers to the server to validate
            RawWrite(connectHeader);

            //将服务器的身份设置为玩家
            // Setup the identity of the server as a player
            server = new NetworkingPlayer(0, host, true, client, this);

            //让我知道我连接成功
            //Let myself know I connected successfully
            OnPlayerConnected(server);
            //将自己设置为连接的客户端
            // Set myself as a connected client
            server.Connected = true;
        }
Beispiel #2
0
        /// <summary>
        /// Setup everything required for this client to be accepted by the server and
        /// construct / send the connection header
        /// </summary>
        /// <param name="port">The port that was connected to on the remote host</param>
        protected virtual void Initialize(string host, ushort port)
        {
            // By default pending creates should be true and flushed when ready
            PendCreates = true;

            // Get a client stream for reading and writing.
            // Stream stream = client.GetStream();

            // Get a random hash key that needs to be used for validating that the server was connected to
            headerHash = Websockets.HeaderHashKey();

            // This is a typical Websockets accept header to be validated
            byte[] connectHeader = Websockets.ConnectionHeader(headerHash, port);

            // Send the accept headers to the server to validate
            RawWrite(connectHeader);

            // Setup the identity of the server as a player
            server = new NetworkingPlayer(0, host, true, client, this);

            //Let myself know I connected successfully
            OnPlayerConnected(server);
            // Set myself as a connected client
            server.Connected = true;
        }
Beispiel #3
0
        private void SetupClient(BMSByte packet, string incomingEndpoint, IPEndPoint groupEP)
        {
            // Check for a local listing request
            if (packet.Size.Between(2, 4) && packet[0] == BROADCAST_LISTING_REQUEST_1 && packet[1] == BROADCAST_LISTING_REQUEST_2 && packet[2] == BROADCAST_LISTING_REQUEST_3)
            {
                // Don't reply if the server is not currently accepting connections
                if (!AcceptingConnections)
                {
                    return;
                }

                // This may be a local listing request so respond with the server flag byte
                Client.Send(new byte[] { SERVER_BROADCAST_CODE }, 1, groupEP);
                return;
            }

            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;
            }

            UDPNetworkingPlayer player = new UDPNetworkingPlayer(ServerPlayerCounter++, incomingEndpoint, false, groupEP, this);

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

            OnPlayerConnected(player);
            udpPlayers.Add(incomingEndpoint, player);

            // The player has successfully connected
            player.Connected = true;
        }
Beispiel #4
0
        // Should validate the handshake response from the server
        private void ReceiveAsync_Completed(object sender, SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
            {
                int          bytesAlreadyProcessed = 0; // Count of the total freshly transferred bytes processed so far
                ReceiveToken token = (ReceiveToken)e.UserToken;
                if (!headerExchanged)
                {
                    byte[] header = HandleHttpHeader(e, ref bytesAlreadyProcessed);
                    token = (ReceiveToken)e.UserToken;
                    if (header == null)
                    {
                        DoRead(e);
                        return;
                    }
                    else if (Websockets.ValidateResponseHeader(headerHash, header))
                    {
                        headerExchanged       = true;
                        token.maxAllowedBytes = int.MaxValue;
                        e.UserToken           = token;

                        // Ping the server to finalize the player's connection
                        Send(Text.CreateFromString(Time.Timestep, InstanceGuid.ToString(), true, Receivers.Server,
                                                   MessageGroupIds.NETWORK_ID_REQUEST, true));
                    }
                    else
                    {
                        // Improper header, so a disconnect is required
                        Disconnect(true);
                        return;
                    }
                }

                while (bytesAlreadyProcessed < e.BytesTransferred)
                {
                    byte[] data = HandleData(e, true, ref bytesAlreadyProcessed);
                    if (data == null)
                    {
                        break;
                    }

                    FrameStream frame = Factory.DecodeMessage(data, false, MessageGroupIds.TCP_FIND_GROUP_ID, Server);

                    FireRead(frame, Server);
                }

                DoRead(e);
            }
            else
            {
                Disconnect(true);
            }
        }
Beispiel #5
0
 private void HandleHeaderExchanging(BMSByte packet)
 {
     if (Websockets.ValidateResponseHeader(headerHash, packet.CompressBytes()))
     {
         CompleteHeaderExchange();
     }
     else if (packet.Size >= MINIMUM_FRAME_SIZE)
     {
         HandleServerRejection(packet);
         CancelReadThread();
     }
     else if (packet.Size != 1 || packet[0] != 0)
     {
         Disconnect(true);
         CancelReadThread();
     }
 }
Beispiel #6
0
        protected virtual void Initialize(string host, ushort port, bool pendCreates = true)
        {
            // By default pending creates should be true and flushed when ready
            if (pendCreates)
            {
                PendCreates = true;
            }

            // Get a random hash key that needs to be used for validating that the server was connected to
            headerHash = Websockets.HeaderHashKey();

            // This is a typical Websockets accept header to be validated
            byte[] connectionHeader = Websockets.ConnectionHeader(headerHash, port);

            // Register the server as a NetworkingPlayer
            server = new NetworkingPlayer(0, host, true, client, this);
            // Send the upgrade request to the server
            RawWrite(connectionHeader);

            //Let myself know I connected successfully
            OnPlayerConnected(server);
            // Set myself as a connected client
            server.Connected = true;

            ReceiveToken token = new ReceiveToken
            {
                internalBuffer  = new ArraySegment <byte>(buffer, 0, buffer.Length),
                player          = server,
                bytesReceived   = 0,
                dataHolder      = null,
                maxAllowedBytes = 8192
            };

            // Read from the server async
            SocketAsyncEventArgs e = new SocketAsyncEventArgs();

            e.Completed += new EventHandler <SocketAsyncEventArgs>(ReceiveAsync_Completed);
            e.UserToken  = token;
            e.SetBuffer(token.internalBuffer.Array, token.internalBuffer.Offset, token.internalBuffer.Count);

            if (!client.Client.ReceiveAsync(e))
            {
                Task.Queue(() => ReceiveAsync_Completed(this, e));
            }
        }
Beispiel #7
0
        private void SetupClient(BMSByte packet, CSteamID 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;
            }

            SteamNetworkingPlayer player = new SteamNetworkingPlayer(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;
        }
Beispiel #8
0
        private void AttemptServerConnection(object _)
        {
            int connectCounter = 0;

            // This is a typical Websockets accept header to be validated
            byte[] connectHeader = Websockets.ConnectionHeader(headerHash, Port);

            do
            {
                // Send the accept headers to the server to validate
                Client.Send(connectHeader, connectHeader.Length, ServerPlayer.IPEndPointHandle);
                Thread.Sleep(3000);
            } while (!initialConnectHeaderExchanged && IsBound && ++connectCounter < CONNECT_TRIES);

            if (connectCounter >= CONNECT_TRIES && connectAttemptFailed != null)
            {
                connectAttemptFailed(this);
            }
        }
Beispiel #9
0
        private void SetNetworkBindings(ushort overrideBindingPort, ushort port, string natHost, string host, ushort natPort)
        {
            // Make sure not to listen on the same port as the server for local networks
            ushort clientPort = FindAvailablePort(overrideBindingPort, port);

            Client.EnableBroadcast = true;

            // If the server is behind a NAT, request for the port punch by the nat server
            if (!string.IsNullOrEmpty(natHost))
            {
                nat.Connect(host, port, clientPort, natHost, natPort);
            }

            // Do any generic initialization in result of the successful bind
            OnBindSuccessful();

            // Get a random hash key that needs to be used for validating that the server was connected to
            headerHash = Websockets.HeaderHashKey();

            // Set the port
            SetPort(clientPort);
        }
Beispiel #10
0
        private void HandleClientAcceptance(BMSByte packet, string incomingEndpoint, IPEndPoint groupEP)
        {
            // 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 UDPNetworkingPlayer(ServerPlayerCounter++, incomingEndpoint,
                                                 false, groupEP, this);

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

            OnPlayerConnected(player);
            udpPlayers.Add(incomingEndpoint, player);

            // The player has successfully connected
            player.Connected = true;
        }
Beispiel #11
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 ReadNetwork()
        {
            CSteamID messageFrom = default(CSteamID);

            try
            {
                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
                    {
                        uint msgSize = 0;

                        if (SteamNetworking.IsP2PPacketAvailable(out msgSize))
                        {
                            packet = Client.Receive(msgSize, out messageFrom);
                        }
                        else
                        {
                            Thread.Sleep(1);
                            continue;
                        }
                        // Read a packet from the network


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

                        BandwidthIn += (ulong)packet.Size;
                    }
                    catch (SocketException ex)
                    {
                        // This is a common exception when we exit the blocking call
                        Logging.BMSLog.LogException(ex);
                        Disconnect(true);
                    }

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

                    // Check to see if the headers have been exchanged
                    if (!headerExchanged)
                    {
                        if (Websockets.ValidateResponseHeader(headerHash, packet.CompressBytes()))
                        {
                            headerExchanged = true;

                            // TODO:  When getting the user id, it should also get the server time
                            // by using the current time in the payload and getting it back along with server time

                            // Ping the server to finalize the player's connection
                            Send(Text.CreateFromString(Time.Timestep, InstanceGuid.ToString(), false, Receivers.Server, MessageGroupIds.NETWORK_ID_REQUEST, false), true);
                        }
                        else if (packet.Size != 1 || packet[0] != 0)
                        {
                            Logging.BMSLog.LogWarning("DISCONNECTED: RECEIVED UNKNOWN PACKET BEFORE HEADERS WERE EXCHANGED!");
                            Disconnect(true);
                            break;
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else
                    {
                        if (packet.Size < 17)
                        {
                            continue;
                        }

                        // Format the byte data into a UDPPacket struct
                        UDPPacket formattedPacket = TranscodePacket(Server, packet);

                        // Check to see if this is a confirmation packet, which is just
                        // a packet to say that the reliable packet has been read
                        if (formattedPacket.isConfirmation)
                        {
                            if (formattedPacket.groupId == MessageGroupIds.DISCONNECT)
                            {
                                CloseConnection();
                                return;
                            }

                            OnMessageConfirmed(server, formattedPacket);
                            continue;
                        }

                        // Add the packet to the manager so that it can be tracked and executed on complete
                        packetManager.AddPacket(formattedPacket, PacketSequenceComplete, this);
                    }
                }
            }
            catch (Exception ex)
            {
                Logging.BMSLog.LogException(ex);
                Disconnect(true);
            }
        }
Beispiel #12
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()
        {
            IPEndPoint groupEP          = new IPEndPoint(IPAddress.Any, 0);
            string     incomingEndpoint = string.Empty;

            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
                {
                    // Read a packet from the network
                    packet = Client.Receive(ref groupEP, ref incomingEndpoint);

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

                    BandwidthIn += (ulong)packet.Size;
                }
                catch
                {
                    if (udpPlayers.ContainsKey(incomingEndpoint))
                    {
                        Disconnect(udpPlayers[incomingEndpoint], true);
                        CleanupDisconnections();
                    }

                    continue;
                }

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

                if (!udpPlayers.ContainsKey(incomingEndpoint))
                {
                    SetupClient(packet, incomingEndpoint, groupEP);
                    continue;
                }
                else
                {
                    currentReadingPlayer = udpPlayers[incomingEndpoint];

                    if (!currentReadingPlayer.Accepted && !currentReadingPlayer.PendingAccpeted)
                    {
                        // 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, groupEP);
                            continue;
                        }
                        else
                        {
                            currentReadingPlayer.PendingAccpeted = true;
                            ReadPacket(packet);
                        }
                    }
                    else
                    {
                        ReadPacket(packet);
                    }
                }
            }
        }
Beispiel #13
0
        /// <summary>
        /// This will connect a UDP client to a given UDP server
        /// </summary>
        /// <param name="host">The server's host address on the network</param>
        /// <param name="port">The port that the server is hosting on</param>
        /// <param name="natHost">The NAT server host address, if blank NAT will be skipped</param>
        /// <param name="natPort">The port that the NAT server is hosting on</param>
        /// <param name="pendCreates">Immidiately set the NetWorker::PendCreates to true</param>
        public void Connect(CSteamID hostId, bool pendCreates = false)
        {
            if (Disposed)
            {
                throw new ObjectDisposedException("UDPClient", "This object has been disposed and can not be used to connect, please use a new UDPClient");
            }

            if (hostId.IsLobby())
            {
                //If this is a lobby we need to join it, make direct connection to the owner.
                m_JoinCall     = SteamMatchmaking.JoinLobby(hostId);
                m_LobbyEntered = Callback <LobbyEnter_t> .Create((LobbyEnter_t data) =>
                {
                    LobbyID = (CSteamID)data.m_ulSteamIDLobby;
                    //Get the owner and attempt a direct connection
                    Connect(SteamMatchmaking.GetLobbyOwner(LobbyID), pendCreates);
                });

                return;
            }
            // By default pending creates should be true and flushed when ready
            if (!pendCreates)
            {
                PendCreates = true;
            }

            try
            {
                ushort clientPort = DEFAULT_PORT;

                // Make sure not to listen on the same port as the server for local networks
                if (clientPort == DEFAULT_PORT)
                {
                    clientPort++;
                }

                Client = new CachedSteamP2PClient(hostId);

                // Do any generic initialization in result of the successful bind
                OnBindSuccessful();

                // Get a random hash key that needs to be used for validating that the server was connected to
                headerHash = Websockets.HeaderHashKey();

                // This is a typical Websockets accept header to be validated
                byte[] connectHeader = Websockets.ConnectionHeader(headerHash, DEFAULT_PORT);

                // Setup the identity of the server as a player
                server = new NetworkingPlayer(0, hostId, true, this);

                // Create the thread that will be listening for new data from connected clients and start its execution
                Task.Queue(ReadNetwork);

                //Let myself know I connected successfully
                OnPlayerConnected(server);

                // Set myself as a connected client
                server.Connected = true;

                //Set the port
                SetPort(clientPort);

                int connectCounter = 0;
                Task.Queue(() =>
                {
                    do
                    {
                        // Send the accept headers to the server to validate
                        Client.Send(connectHeader, connectHeader.Length, hostId, EP2PSend.k_EP2PSendReliable);
                        Thread.Sleep(3000);
                    } while (!headerExchanged && IsBound && ++connectCounter < CONNECT_TRIES);

                    if (connectCounter >= CONNECT_TRIES)
                    {
                        if (connectAttemptFailed != null)
                        {
                            connectAttemptFailed(this);
                        }
                    }
                });

                m_CallbackP2PSessionConnectFail = Callback <P2PSessionConnectFail_t> .Create((P2PSessionConnectFail_t data) =>
                {
                    if (data.m_eP2PSessionError > 0)
                    {
                        Disconnect(true);
                        switch (data.m_eP2PSessionError)
                        {
                        case 1:
                            Logging.BMSLog.LogException("The target user is not running the same game."); break;

                        case 2:
                            Logging.BMSLog.LogException("The local user doesn't own the app that is running."); break;

                        case 3:
                            Logging.BMSLog.LogException("Target user isn't connected to Steam."); break;

                        case 4:
                            Logging.BMSLog.LogException("The connection timed out because the target user didn't respond, perhaps they aren't calling AcceptP2PSessionWithUser"); break;
                        }
                    }
                    //
                });
            }
            catch (Exception e)
            {
                Logging.BMSLog.LogException(e);
                // Do any generic initialization in result of the binding failure
                OnBindFailure();

                throw new FailedBindingException("Failed to bind to host/port, see inner exception", e);
            }
        }
        /// <summary>
        /// This will connect a UDP client to a given UDP server
        /// </summary>
        /// <param name="host">The server's host address on the network</param>
        /// <param name="port">The port that the server is hosting on</param>
        /// <param name="natHost">The NAT server host address, if blank NAT will be skipped</param>
        /// <param name="natPort">The port that the NAT server is hosting on</param>
        /// <param name="pendCreates">Immidiately set the NetWorker::PendCreates to true</param>
        public void Connect(string host, ushort port = DEFAULT_PORT, string natHost = "", ushort natPort = NatHolePunch.DEFAULT_NAT_SERVER_PORT, bool pendCreates = false, ushort overrideBindingPort = DEFAULT_PORT + 1)
        {
            if (Disposed)
            {
                throw new ObjectDisposedException("UDPClient", "This object has been disposed and can not be used to connect, please use a new UDPClient");
            }

            // By default pending creates should be true and flushed when ready
            if (!pendCreates)
            {
                PendCreates = true;
            }

            try
            {
                ushort clientPort = overrideBindingPort;

                // Make sure not to listen on the same port as the server for local networks
                if (clientPort == port)
                {
                    clientPort++;
                }

                for (; ; clientPort++)
                {
                    try
                    {
                        Client = new CachedUdpClient(clientPort);
                        break;
                    }
                    catch
                    {
                        if (port == 0)
                        {
                            throw new BaseNetworkException("There were no ports available starting from port " + port);
                        }
                    }
                }

                Client.EnableBroadcast = true;

                // If the server is behind a NAT, request for the port punch by the nat server
                if (!string.IsNullOrEmpty(natHost))
                {
                    nat.Connect(host, port, clientPort, natHost, natPort);
                }

                // Do any generic initialization in result of the successful bind
                OnBindSuccessful();

                // Get a random hash key that needs to be used for validating that the server was connected to
                headerHash = Websockets.HeaderHashKey();

                // This is a typical Websockets accept header to be validated
                byte[] connectHeader = Websockets.ConnectionHeader(headerHash, port);

                try
                {
                    // Setup the identity of the server as a player
                    server = new NetworkingPlayer(0, host, true, ResolveHost(host, port), this);
                }
                catch (ArgumentException)
                {
                    if (connectAttemptFailed != null)
                    {
                        connectAttemptFailed(this);
                    }

                    throw;
                }

                // Create the thread that will be listening for new data from connected clients and start its execution
                Task.Queue(ReadNetwork);

                //Let myself know I connected successfully
                OnPlayerConnected(server);

                // Set myself as a connected client
                server.Connected = true;

                //Set the port
                SetPort(clientPort);

                int connectCounter = 0;
                Task.Queue(() =>
                {
                    do
                    {
                        // Send the accept headers to the server to validate
                        Client.Send(connectHeader, connectHeader.Length, Server.IPEndPointHandle);
                        Thread.Sleep(3000);
                    } while (!headerExchanged && IsBound && ++connectCounter < CONNECT_TRIES);

                    if (connectCounter >= CONNECT_TRIES)
                    {
                        if (connectAttemptFailed != null)
                        {
                            connectAttemptFailed(this);
                        }
                    }
                });
            }
            catch (Exception e)
            {
                Logging.BMSLog.LogException(e);
                // Do any generic initialization in result of the binding failure
                OnBindFailure();

                throw new FailedBindingException("Failed to bind to host/port, see inner exception", e);
            }
        }
Beispiel #15
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()
        {
            IPEndPoint groupEP          = new IPEndPoint(IPAddress.Any, 0);
            string     incomingEndpoint = string.Empty;

            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
                {
                    // Read a packet from the network
                    packet = Client.Receive(ref groupEP, ref incomingEndpoint);

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

                    BandwidthIn += (ulong)packet.Size;
                }
                catch
                {
                    UDPNetworkingPlayer player;
                    if (udpPlayers.TryGetValue(incomingEndpoint, out player))
                    {
                        FinalizeRemovePlayer(player, true);
                    }

                    continue;
                }

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

                if (!udpPlayers.ContainsKey(incomingEndpoint))
                {
                    SetupClient(packet, incomingEndpoint, groupEP);
                    continue;
                }
                else
                {
                    currentReadingPlayer = udpPlayers[incomingEndpoint];

                    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, groupEP);
                            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)
                        {
                            udpPlayers.Remove(currentReadingPlayer.Ip + "+" + currentReadingPlayer.Port);
                            FinalizeRemovePlayer(currentReadingPlayer, true);
                            continue;
                        }

                        currentReadingPlayer.Ping();
                        ReadPacket(packet);
                    }
                }
            }
        }
Beispiel #16
0
        /// <summary>
        /// Connect this FacepunchP2PClient directly to a steam user's FacepunchP2PServer with SteamId specified
        /// </summary>
        /// <param name="hostId">The host's <see cref="SteamId"/> SteamId object</param>
        /// <param name="pendCreates">Immediately set the NetWorker::PendCreates to true</param>
        public void Connect(SteamId hostId, bool pendCreates = false)
        {
            if (Disposed)
            {
                throw new ObjectDisposedException("FacepunchP2PClient", "This object has been disposed and can not be used to connect, please use a new FacepunchP2PClient");
            }

            // By default pending creates should be true and flushed when ready
            if (!pendCreates)
            {
                PendCreates = true;
            }

            try
            {
                ushort clientPort = DEFAULT_PORT;

                // Make sure not to listen on the same port as the server for local networks
                if (clientPort == DEFAULT_PORT)
                {
                    clientPort++;
                }

                Client = new CachedFacepunchP2PClient(hostId);

                // Do any generic initialization in result of the successful bind
                OnBindSuccessful();

                // Get a random hash key that needs to be used for validating that the server was connected to
                headerHash = Websockets.HeaderHashKey();

                // This is a typical Websockets accept header to be validated
                byte[] connectHeader = Websockets.ConnectionHeader(headerHash, DEFAULT_PORT);

                // Setup the identity of the server as a player
                server = new NetworkingPlayer(0, hostId, true, this);

                // Create the thread that will be listening for new data from connected clients and start its execution
                Task.Queue(ReadNetwork);

                //Let myself know I connected successfully
                OnPlayerConnected(server);

                // Set myself as a connected client
                server.Connected = true;

                //Set the port
                SetPort(clientPort);

                int connectCounter = 0;
                Task.Queue(() =>
                {
                    do
                    {
                        // Send the accept headers to the server to validate
                        Client.Send(connectHeader, connectHeader.Length, hostId, P2PSend.Reliable);
                        Thread.Sleep(3000);
                    } while (!headerExchanged && IsBound && ++connectCounter < CONNECT_TRIES);

                    if (connectCounter >= CONNECT_TRIES)
                    {
                        if (connectAttemptFailed != null)
                        {
                            connectAttemptFailed(this);
                        }
                    }
                });
            }
            catch (Exception e)
            {
                Logging.BMSLog.LogException(e);
                // Do any generic initialization in result of the binding failure
                OnBindFailure();

                throw new FailedBindingException("Failed to bind to server's SteamId, see inner exception", e);
            }
        }
        /// <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 ReadNetwork()
        {
            IPEndPoint groupEP          = new IPEndPoint(IPAddress.Any, 0);
            string     incomingEndpoint = string.Empty;

            try
            {
                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
                    {
                        // Read a packet from the network
                        packet = Client.Receive(ref groupEP, ref incomingEndpoint);

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

                        BandwidthIn += (ulong)packet.Size;
                    }
                    catch (SocketException /*ex*/)
                    {
                        // This is a common exception when we exit the blocking call
                        //Logging.BMSLog.LogException(ex);
                        Disconnect(true);
                    }

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

                    // This message was not from the server
                    if (groupEP.Address != Server.IPEndPointHandle.Address &&
                        groupEP.Port != Server.IPEndPointHandle.Port)
                    {
                        if (packet.Size == 1 && (packet[0] == SERVER_BROADCAST_CODE || packet[1] == CLIENT_BROADCAST_CODE))
                        {
                        }
                        else if (packet.Size.Between(2, 4) && packet[0] == BROADCAST_LISTING_REQUEST_1 && packet[1] == BROADCAST_LISTING_REQUEST_2 && packet[2] == BROADCAST_LISTING_REQUEST_3)
                        {
                            // This may be a local listing request so respond with the client flag byte
                            Client.Send(new byte[] { CLIENT_BROADCAST_CODE }, 1, groupEP);
                        }

                        continue;
                    }

                    // Check to see if the headers have been exchanged
                    if (!headerExchanged)
                    {
                        if (Websockets.ValidateResponseHeader(headerHash, packet.CompressBytes()))
                        {
                            headerExchanged = true;

                            // TODO:  When getting the user id, it should also get the server time
                            // by using the current time in the payload and getting it back along with server time

                            // Ping the server to finalize the player's connection
                            Send(Text.CreateFromString(Time.Timestep, InstanceGuid.ToString(), false, Receivers.Server, MessageGroupIds.NETWORK_ID_REQUEST, false), true);
                        }
                        else if (packet.Size >= MINIMUM_FRAME_SIZE)
                        {
                            // The server sent us a message before sending a responseheader to validate
                            // This happens if the server is not accepting connections or the max connection count has been reached
                            // We will get two messages. The first one is either a MAX_CONNECTIONS or NOT_ACCEPT_CONNECTIONS group message.
                            // The second one will be the DISCONNECT message
                            UDPPacket formattedPacket = TranscodePacket(Server, packet);

                            if (formattedPacket.groupId == MessageGroupIds.MAX_CONNECTIONS)
                            {
                                Logging.BMSLog.LogWarning("Max Players Reached On Server");
                                // Wait for the second message (Disconnect)
                                continue;
                            }

                            if (formattedPacket.groupId == MessageGroupIds.NOT_ACCEPT_CONNECTIONS)
                            {
                                Logging.BMSLog.LogWarning("The server is busy and not accepting connections");
                                // Wait for the second message (Disconnect)
                                continue;
                            }

                            if (formattedPacket.groupId == MessageGroupIds.DISCONNECT)
                            {
                                CloseConnection();
                                return;
                            }

                            // Received something unexpected so do the same thing as the if below
                            Disconnect(true);
                            break;
                        }
                        else if (packet.Size != 1 || packet[0] != 0)
                        {
                            Disconnect(true);
                            break;
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else
                    {
                        if (packet.Size < MINIMUM_FRAME_SIZE)
                        {
                            continue;
                        }

                        // Format the byte data into a UDPPacket struct
                        UDPPacket formattedPacket = TranscodePacket(Server, packet);

                        // Check to see if this is a confirmation packet, which is just
                        // a packet to say that the reliable packet has been read
                        if (formattedPacket.isConfirmation)
                        {
                            if (formattedPacket.groupId == MessageGroupIds.DISCONNECT)
                            {
                                CloseConnection();
                                return;
                            }

                            OnMessageConfirmed(server, formattedPacket);
                            continue;
                        }

                        if (formattedPacket.groupId == MessageGroupIds.AUTHENTICATION_FAILURE)
                        {
                            Logging.BMSLog.LogWarning("The server rejected the authentication attempt");
                            // Wait for the second message (Disconnect)
                            continue;
                        }

                        // Add the packet to the manager so that it can be tracked and executed on complete
                        packetManager.AddPacket(formattedPacket, PacketSequenceComplete, this);
                    }
                }
            }
            catch (Exception ex)
            {
                Logging.BMSLog.LogException(ex);
                Disconnect(true);
            }
        }
Beispiel #18
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()
        {
            IPEndPoint groupEP          = new IPEndPoint(IPAddress.Any, 0);
            string     incomingEndpoint = string.Empty;

            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
                {
                    // Read a packet from the network
                    packet = Client.Receive(ref groupEP, ref incomingEndpoint);
                    if (PacketLossSimulation > 0.0f && new Random().NextDouble() <= PacketLossSimulation)
                    {
                        // Skip this message
                        continue;
                    }

                    BandwidthIn += (ulong)packet.Size;
                }
                catch (Exception ex) when(!(ex is SocketException))
                {
                    Console.WriteLine($"Error in ReadClients() infinite loop, error was {ex.Message}");

                    UDPNetworkingPlayer player;

                    if (udpPlayers.TryGetValue(incomingEndpoint, out player))
                    {
                        Console.WriteLine($"Following the error, player '{player.NetworkId}' will be removed");
                        FinalizeRemovePlayer(player, true);
                    }

                    continue;
                }

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

                if (!udpPlayers.ContainsKey(incomingEndpoint))
                {
                    SetupClient(packet, incomingEndpoint, groupEP);
                    continue;
                }
                else
                {
                    currentReadingPlayer = udpPlayers[incomingEndpoint];

                    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, groupEP);
                            continue;
                        }
                        else
                        {
                            currentReadingPlayer.PendingAccepted = true;
                            ReadPacket(packet);
                        }
                    }
                    else
                    {
                        currentReadingPlayer.Ping();
                        ReadPacket(packet);
                    }
                }
            }
        }
Beispiel #19
0
        public void Connect(string host, ushort port = DEFAULT_PORT, string natHost = "", ushort natPort = NatHolePunch.DEFAULT_NAT_SERVER_PORT, bool isSpecial = false)
        {
            // By default pending creates should be true and flushed when ready
            if (!isSpecial)
            {
                PendCreates = true;
            }

            try
            {
                // TODO:  Remove + 1, it is for linux tests
                ushort clientPort = port;                //(ushort)(port + 1);
                for (; ; clientPort++)
                {
                    try
                    {
                        Client = new CachedUdpClient(clientPort);
                        break;
                    }
                    catch
                    {
                        if (port == 0)
                        {
                            throw new BaseNetworkException("There were no ports available starting from port " + port);
                        }
                    }
                }

                Client.EnableBroadcast = true;

                // If the server is behind a NAT, request for the port punch by the nat server
                if (!string.IsNullOrEmpty(natHost))
                {
                    nat.Connect(host, port, clientPort, natHost, natPort);
                }

                // Do any generic initialization in result of the successful bind
                OnBindSuccessful();

                // Get a random hash key that needs to be used for validating that the server was connected to
                headerHash = Websockets.HeaderHashKey();

                // This is a typical Websockets accept header to be validated
                byte[] connectHeader = Websockets.ConnectionHeader(headerHash, port);

                // Setup the identity of the server as a player
                server = new NetworkingPlayer(0, host, true, ResolveHost(host, port), this);

                // Create the thread that will be listening for new data from connected clients and start its execution
                Task.Queue(ReadNetwork);

                //Let myself know I connected successfully
                OnPlayerConnected(server);
                // Set myself as a connected client
                server.Connected = true;
                //Set the port
                SetPort(clientPort);

                Task.Queue(() =>
                {
                    do
                    {
                        // Send the accept headers to the server to validate
                        Client.Send(connectHeader, connectHeader.Length, Server.IPEndPointHandle);

                        Thread.Sleep(3000);
                    } while (!headerExchanged && IsBound);
                });
            }
            catch (Exception e)
            {
                Logging.BMSLog.LogException(e);
                // Do any generic initialization in result of the binding failure
                OnBindFailure();

                throw new FailedBindingException("Failed to bind to host/port, see inner exception", e);
            }
        }
        /// <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>
        /// <summary>
        ///无限循环在单独的线程上监听来自所有连接客户端的新数据。
        ///当readThreadCancel设置为true时,此循环中断
        /// </ summary>
        private void ReadNetwork()
        {
            IPEndPoint groupEP          = new IPEndPoint(IPAddress.Any, 0);
            string     incomingEndpoint = string.Empty;

            try
            {
                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
                    {
                        // Read a packet from the network
                        packet = Client.Receive(ref groupEP, ref incomingEndpoint);

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

                        BandwidthIn += (ulong)packet.Size;
                    }
                    catch (SocketException /*ex*/)
                    {
                        // This is a common exception when we exit the blocking call
                        //Logging.BMSLog.LogException(ex);
                        Disconnect(true);
                    }

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

                    // This message was not from the server
                    if (groupEP.Address != Server.IPEndPointHandle.Address &&
                        groupEP.Port != Server.IPEndPointHandle.Port)
                    {
                        if (packet.Size == 1 && (packet[0] == SERVER_BROADCAST_CODE || packet[1] == CLIENT_BROADCAST_CODE))
                        {
                        }
                        else if (packet.Size.Between(2, 4) && packet[0] == BROADCAST_LISTING_REQUEST_1 && packet[1] == BROADCAST_LISTING_REQUEST_2 && packet[2] == BROADCAST_LISTING_REQUEST_3)
                        {
                            //这可能是一个本地列表请求,所以用客户端标志字节进行响应
                            // This may be a local listing request so respond with the client flag byte
                            Client.Send(new byte[] { CLIENT_BROADCAST_CODE }, 1, groupEP);
                        }

                        continue;
                    }

                    // Check to see if the headers have been exchanged
                    if (!headerExchanged)
                    {
                        if (Websockets.ValidateResponseHeader(headerHash, packet.CompressBytes()))
                        {
                            headerExchanged = true;

                            // TODO:  When getting the user id, it should also get the server time
                            // by using the current time in the payload and getting it back along with server time

                            // Ping the server to finalize the player's connection
                            Send(Text.CreateFromString(Time.Timestep, InstanceGuid.ToString(), false, Receivers.Server, MessageGroupIds.NETWORK_ID_REQUEST, false), true);
                        }
                        else if (packet.Size != 1 || packet[0] != 0)
                        {
                            Disconnect(true);
                            break;
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else
                    {
                        if (packet.Size < 17)
                        {
                            continue;
                        }

                        // 格式的字节数据到一个udppacket结构
                        // Format the byte data into a UDPPacket struct
                        UDPPacket formattedPacket = TranscodePacket(Server, packet);

                        // Check to see if this is a confirmation packet, which is just
                        // a packet to say that the reliable packet has been read
                        if (formattedPacket.isConfirmation)
                        {
                            if (formattedPacket.groupId == MessageGroupIds.DISCONNECT)
                            {
                                CloseConnection();
                                return;
                            }

                            OnMessageConfirmed(server, formattedPacket);
                            continue;
                        }

                        //将数据包添加到管理器,以便可以在完成时跟踪和执行
                        // Add the packet to the manager so that it can be tracked and executed on complete
                        packetManager.AddPacket(formattedPacket, PacketSequenceComplete, this);
                    }
                }
            }
            catch (Exception ex)
            {
                Logging.BMSLog.LogException(ex);
                Disconnect(true);
            }
        }
        /// <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()
        {
            // Intentional infinite loop
            while (IsBound && !NetWorker.EndingSession)
            {
                try
                {
                    // If the read has been flagged to be canceled then break from this loop
                    if (readThreadCancel)
                    {
                        return;
                    }

                    // This will loop through all of the players, so make sure to set the lock to
                    // prevent any changes from other threads
                    lock (Players)
                    {
                        for (int i = 0; i < Players.Count; i++)
                        {
                            // If the read has been flagged to be canceled then break from this loop
                            if (readThreadCancel)
                            {
                                return;
                            }

                            NetworkStream playerStream = null;

                            if (Players[i].IsHost)
                            {
                                continue;
                            }

                            try
                            {
                                lock (Players[i].MutexLock)
                                {
                                    // Try to get the client stream if it is still available
                                    playerStream = Players[i].TcpClientHandle.GetStream();
                                }
                            }
                            catch
                            {
                                // Failed to get the stream for the client so forcefully disconnect it
                                //Console.WriteLine("Exception: Failed to get stream for client (Forcefully disconnecting)");
                                Disconnect(Players[i], true);
                                continue;
                            }

                            // If the player is no longer connected, then make sure to disconnect it properly
                            if (!Players[i].TcpClientHandle.Connected)
                            {
                                Disconnect(Players[i], false);
                                continue;
                            }

                            // Only continue to read for this client if there is any data available for it
                            if (!playerStream.DataAvailable)
                            {
                                continue;
                            }

                            int available = Players[i].TcpClientHandle.Available;

                            // Determine if the player is fully connected
                            if (!Players[i].Accepted)
                            {
                                // Determine if the player has been accepted by the server
                                if (!Players[i].Connected)
                                {
                                    lock (Players[i].MutexLock)
                                    {
                                        // Read everything from the stream as the client hasn't been accepted yet
                                        byte[] bytes = new byte[available];
                                        playerStream.Read(bytes, 0, bytes.Length);

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

                                        // 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)
                                        {
                                            OnPlayerRejected(Players[i]);
                                            Disconnect(Players[i], false);
                                            continue;
                                        }

                                        // If all is in order then send the validated response to the client
                                        playerStream.Write(response, 0, response.Length);

                                        // The player has successfully connected
                                        Players[i].Connected = true;
                                    }
                                }
                                else
                                {
                                    lock (Players[i].MutexLock)
                                    {
                                        // Consume the message even though it is not being used so that it is removed from the buffer
                                        Text frame = (Text)Factory.DecodeMessage(GetNextBytes(playerStream, available, true), true, MessageGroupIds.TCP_FIND_GROUP_ID, Players[i]);
                                        Players[i].InstanceGuid = frame.ToString();

                                        OnPlayerGuidAssigned(Players[i]);

                                        lock (writeBuffer)
                                        {
                                            writeBuffer.Clear();
                                            writeBuffer.Append(BitConverter.GetBytes(Players[i].NetworkId));
                                            Send(Players[i].TcpClientHandle, new Binary(Time.Timestep, false, writeBuffer, Receivers.Target, MessageGroupIds.NETWORK_ID_REQUEST, true));

                                            SendBuffer(Players[i]);

                                            // All systems go, the player has been accepted
                                            OnPlayerAccepted(Players[i]);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                try
                                {
                                    lock (Players[i].MutexLock)
                                    {
                                        Players[i].Ping();

                                        // Get the frame that was sent by the client, the client
                                        // does send masked data
                                        //TODO: THIS IS CAUSING ISSUES!!! WHY!?!?!!?
                                        FrameStream frame = Factory.DecodeMessage(GetNextBytes(playerStream, available, true), true, MessageGroupIds.TCP_FIND_GROUP_ID, Players[i]);

                                        // The client has told the server that it is disconnecting
                                        if (frame is ConnectionClose)
                                        {
                                            // Confirm the connection close
                                            Send(Players[i].TcpClientHandle, new ConnectionClose(Time.Timestep, false, Receivers.Target, MessageGroupIds.DISCONNECT, true));

                                            Disconnect(Players[i], false);
                                            continue;
                                        }

                                        FireRead(frame, Players[i]);
                                    }
                                }
                                catch
                                {
                                    // The player is sending invalid data so disconnect them
                                    Disconnect(Players[i], true);
                                }
                            }
                        }
                    }

                    // Go through all of the pending disconnections and clean them
                    // up and finalize the disconnection
                    CleanupDisconnections();

                    // Sleep so that we free up the CPU a bit from this thread
                    Thread.Sleep(10);
                }
                catch (Exception ex)
                {
                    Logging.BMSLog.LogException(ex);
                }
            }
        }
        /// <summary>
        /// 无限循环在单独的线程上监听来自所有连接客户端的新数据。
        /// readThreadCancel设置为true时,此循环会中断
        ///
        /// Infinite loop listening for new data from all connected clients on a separate thread.
        /// This loop breaks when readThreadCancel is set to true
        /// </summary>
        protected ReadState Read()
        {
            if (disconnectedSelf)
            {
                return(ReadState.Disconnect);
            }

            NetworkStream stream = client.GetStream();

            if (stream == null)             //Some reason the stream is null! //某些原因流为空!
            {
                return(ReadState.Continue);
            }

            //如果流不再可读,则断开连接
            // If the stream no longer can read then disconnect
            if (!stream.CanRead)
            {
                Disconnect(true);
                return(ReadState.Disconnect);
            }

            //如果没有可用的数据,则通过休眠线程释放CPU
            // If there isn't any data available, then free up the CPU by sleeping the thread
            if (!stream.DataAvailable)
            {
                return(ReadState.Continue);
            }

            int available = client.Available;

            if (available == 0)
            {
                return(ReadState.Continue);
            }

            //确定这个客户端是否已被服务器接受
            // Determine if this client has been accepted by the server yet
            if (!headerExchanged)
            {
                //读取流中所有可用的字节,因为这个客户端还没有连接
                // Read all available bytes in the stream as this client hasn't connected yet
                byte[] bytes = new byte[available];
                stream.Read(bytes, 0, bytes.Length);

                //来自服务器的第一个数据包响应将是一个字符串
                // The first packet response from the server is going to be a string
                if (Websockets.ValidateResponseHeader(headerHash, bytes))
                {
                    headerExchanged = true;

                    //通过Ping服务器来确定玩家的连接
                    // Ping the server to finalize the player's connection
                    Send(Text.CreateFromString(Time.Timestep, InstanceGuid.ToString(), true, Receivers.Server, MessageGroupIds.NETWORK_ID_REQUEST, true));
                }
                else
                {
                    // Improper header, so a disconnect is required
                    Disconnect(true);
                    return(ReadState.Disconnect);
                }
            }
            else
            {
                byte[] messageBytes = GetNextBytes(stream, available, false);

                //获取由服务器,服务器发送的帧
                //不发送被屏蔽的数据,只有客户端发送false为掩码
                // Get the frame that was sent by the server, the server
                // does not send masked data, only the client so send false for mask
                FrameStream frame = Factory.DecodeMessage(messageBytes, false, MessageGroupIds.TCP_FIND_GROUP_ID, Server);

                FireRead(frame, Server);
            }

            return(ReadState.Void);
        }
Beispiel #23
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()
        {
            CSteamID messageFrom = default(CSteamID);

            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
                {
                    // Read a packet from the network
                    uint msgSize = 0;

                    if (SteamNetworking.IsP2PPacketAvailable(out msgSize))
                    {
                        packet = Client.Receive(msgSize, out messageFrom);
                    }
                    else
                    {
                        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);

                    SteamNetworkingPlayer 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, EP2PSend.k_EP2PSendReliable);
                            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);
                    }
                }
            }
        }
Beispiel #24
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>
        protected ReadState Read()
        {
            if (disconnectedSelf)
            {
                return(ReadState.Disconnect);
            }

            NetworkStream stream = client.GetStream();

            if (stream == null)             //Some reason the stream is null!
            {
                return(ReadState.Continue);
            }

            // If the stream no longer can read then disconnect
            if (!stream.CanRead)
            {
                Disconnect(true);
                return(ReadState.Disconnect);
            }

            // If there isn't any data available, then free up the CPU by sleeping the thread
            if (!stream.DataAvailable)
            {
                return(ReadState.Continue);
            }

            int available = client.Available;

            if (available == 0)
            {
                return(ReadState.Continue);
            }

            // Determine if this client has been accepted by the server yet
            if (!headerExchanged)
            {
                // Read all available bytes in the stream as this client hasn't connected yet
                byte[] bytes = new byte[available];
                stream.Read(bytes, 0, bytes.Length);

                // The first packet response from the server is going to be a string
                if (Websockets.ValidateResponseHeader(headerHash, bytes))
                {
                    headerExchanged = true;

                    // Ping the server to finalize the player's connection
                    Send(Text.CreateFromString(Time.Timestep, InstanceGuid.ToString(), true, Receivers.Server, MessageGroupIds.NETWORK_ID_REQUEST, true));
                }
                else
                {
                    // Improper header, so a disconnect is required
                    Disconnect(true);
                    return(ReadState.Disconnect);
                }
            }
            else
            {
                byte[] messageBytes = GetNextBytes(stream, available, false);

                // Get the frame that was sent by the server, the server
                // does not send masked data, only the client so send false for mask
                FrameStream frame = Factory.DecodeMessage(messageBytes, false, MessageGroupIds.TCP_FIND_GROUP_ID, Server);

                if (frame is ConnectionClose)
                {
                    // Close our CachedUDPClient so that it can no longer be used
                    client.Close();
                    return(ReadState.Disconnect);
                }

                // A message has been successfully read from the network so relay that
                // to all methods registered to the event
                OnMessageReceived(Server, frame);
            }

            return(ReadState.Void);
        }
Beispiel #25
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>
        /// <summary>
        ///无限循环在单独的线程上监听来自所有连接客户端的新数据。
        ///当readThreadCancel设置为true时,此循环中断
        /// </ summary>
        private void ReadClients()
        {
            IPEndPoint groupEP          = new IPEndPoint(IPAddress.Any, 0);
            string     incomingEndpoint = string.Empty;

            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
                {
                    //从网络读取数据包
                    // Read a packet from the network
                    packet = Client.Receive(ref groupEP, ref incomingEndpoint);

                    // 模拟丢包
                    if (PacketLossSimulation > 0.0f && new Random().NextDouble() <= PacketLossSimulation)
                    {
                        // 丢掉这个消息
                        // Skip this message
                        continue;
                    }
                    // 统计 宽带接收数据大小
                    BandwidthIn += (ulong)packet.Size;
                }
                catch
                {
                    // 如果出错, 就查找该IP PROT的玩家,将该玩家踢掉
                    UDPNetworkingPlayer player;
                    if (udpPlayers.TryGetValue(incomingEndpoint, out player))
                    {
                        FinalizeRemovePlayer(player, true);
                    }

                    continue;
                }

                //检查以确保收到消息
                // Check to make sure a message was received
                if (packet == null || packet.Size <= 0)
                {
                    continue;
                }

                //如果玩家列表里不包含该包的发送者
                if (!udpPlayers.ContainsKey(incomingEndpoint))
                {
                    // 创建该发送者的结构体保存 UDPNetworkingPlayer
                    SetupClient(packet, incomingEndpoint, groupEP);
                    continue;
                }
                else
                {
                    currentReadingPlayer = udpPlayers[incomingEndpoint];

                    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, groupEP);
                            continue;
                        }
                        else
                        {
                            // 将该玩家设置为等待接受确认
                            currentReadingPlayer.PendingAccepted = true;
                            // 读取该玩家发来的数据包
                            ReadPacket(packet);
                        }
                    }
                    else
                    {
                        //由于Forge网络协议,数据包唯一的时间1
                        //将是71,第二个数据包是69是强制断开连接
                        // 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)
                        {
                            udpPlayers.Remove(currentReadingPlayer.Ip + "+" + currentReadingPlayer.Port);
                            FinalizeRemovePlayer(currentReadingPlayer, true);
                            continue;
                        }

                        // 设置玩家最好ping时间
                        currentReadingPlayer.Ping();
                        // 读取该玩家发来的数据包
                        ReadPacket(packet);
                    }
                }
            }
        }
Beispiel #26
0
        private void ReceiveAsync_Completed(object sender, SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success)
            {
                int          bytesAlreadyProcessed = 0;
                ReceiveToken token = (ReceiveToken)e.UserToken;
                if (!token.player.Accepted && !token.player.Connected)
                {
                    byte[] header = HandleHttpHeader(e, ref bytesAlreadyProcessed);
                    if (header == null)
                    {
                        DoRead(e);
                        return;
                    }
                    byte[] response = Websockets.ValidateConnectionHeader(header);

                    // 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)
                    {
                        OnPlayerRejected(token.player);
                        Disconnect(token.player, true);
                        ReturnBuffer(e);
                        return;
                    }

                    // If all is in order then send the validated response to the client
                    token.player.TcpClientHandle.GetStream().Write(response, 0, response.Length);

                    // The player has successfully connected
                    token.player.Connected = true;
                }
                while (bytesAlreadyProcessed < e.BytesTransferred)
                {
                    byte[] data = HandleData(e, true, ref bytesAlreadyProcessed);
                    if (data == null)
                    {
                        break;
                    }
                    FrameStream frame = Factory.DecodeMessage(data, true, MessageGroupIds.TCP_FIND_GROUP_ID, token.player);
                    if (!token.player.Accepted)
                    {
                        if (frame.GroupId == MessageGroupIds.NETWORK_ID_REQUEST)
                        {
                            token.player.InstanceGuid = ((Text)frame).ToString();

                            // If the player was rejected during the handling of the playerGuidAssigned event, don't accept them.
                            if (!TryPlayerGuidAssignment(token.player))
                            {
                                break;
                            }

                            token.maxAllowedBytes = int.MaxValue;

                            if (authenticator != null)
                            {
                                authenticator.IssueChallenge(this, token.player, IssueChallenge, AuthUser);
                            }
                            else
                            {
                                AuthUser(token.player);
                            }
                        }
                        else if (frame.GroupId == MessageGroupIds.AUTHENTICATION_RESPONSE)
                        {
                            // Authenticate user response
                            if (authenticator == null)
                            {
                                return;
                            }

                            authenticator.VerifyResponse(this, token.player, frame.StreamData, AuthUser, RejectUser);
                        }
                        else
                        {
                            Disconnect(token.player, true);
                            ReturnBuffer(e);
                        }
                    }
                    else
                    {
                        token.player.Ping();
                        FireRead(frame, token.player);
                    }
                }
                DoRead(e);
            }
            else
            {
                Disconnect(((ReceiveToken)e.UserToken).player, true);
                ReturnBuffer(e);
            }
        }