Beispiel #1
0
        // encrypts a packet and sends it to the endpoint
        private void sendPacketToClient(NetcodePacketHeader packetHeader, byte[] packetData, int packetDataLen, EndPoint endpoint, byte[] key)
        {
            // assign a sequence number to this packet
            packetHeader.SequenceNumber = this.nextSequenceNumber++;

            // encrypt packet data
            byte[] encryptedPacketBuffer = BufferPool.GetBuffer(2048);

            int encryptedBytes = PacketIO.EncryptPacketData(packetHeader, protocolID, packetData, packetDataLen, key, encryptedPacketBuffer);

            int packetLen = 0;

            // write packet to byte array
            var packetBuffer = BufferPool.GetBuffer(2048);

            using (var packetWriter = ByteArrayReaderWriter.Get(packetBuffer))
            {
                packetHeader.Write(packetWriter);
                packetWriter.WriteBuffer(encryptedPacketBuffer, encryptedBytes);

                packetLen = (int)packetWriter.WritePosition;
            }

            // send packet
            listenSocket.SendTo(packetBuffer, packetLen, endpoint);

            BufferPool.ReturnBuffer(packetBuffer);
            BufferPool.ReturnBuffer(encryptedPacketBuffer);
        }
Beispiel #2
0
        private void processConnectionKeepAlive(NetcodePacketHeader header, int length, ByteArrayReaderWriter stream)
        {
            if (checkReplay(header))
            {
                return;
            }

            var decryptKey = serverToClientKey;
            var keepAlive  = new NetcodeKeepAlivePacket()
            {
                Header = header
            };

            if (!keepAlive.Read(stream, length, decryptKey, connectToken.ProtocolID))
            {
                return;
            }

            if (this.state == ClientState.Connected || this.state == ClientState.SendingChallengeResponse)
            {
                lastResponseTime = time;
            }

            if (this.state == ClientState.SendingChallengeResponse)
            {
                this.clientIndex = keepAlive.ClientIndex;
                this.maxSlots    = keepAlive.MaxSlots;
                changeState(ClientState.Connected);
            }
        }
Beispiel #3
0
        private void processConnectionPayload(NetcodePacketHeader header, int length, ByteArrayReaderWriter stream)
        {
            if (checkReplay(header))
            {
                return;
            }
            if (this.state != ClientState.Connected)
            {
                return;
            }

            var decryptKey    = serverToClientKey;
            var payloadPacket = new NetcodePayloadPacket()
            {
                Header = header
            };

            if (!payloadPacket.Read(stream, length, decryptKey, connectToken.ProtocolID))
            {
                return;
            }

            lastResponseTime = time;
            if (OnMessageReceived != null)
            {
                OnMessageReceived(payloadPacket.Payload, payloadPacket.Length);
            }

            payloadPacket.Release();
        }
Beispiel #4
0
        private void serializePacket(NetcodePacketHeader packetHeader, Action <ByteArrayReaderWriter> write, EndPoint endpoint, byte[] key)
        {
            byte[] tempPacket = BufferPool.GetBuffer(2048);
            int    writeLen   = 0;

            using (var writer = ByteArrayReaderWriter.Get(tempPacket))
            {
                write(writer);
                writeLen = (int)writer.WritePosition;
            }

            sendPacketToClient(packetHeader, tempPacket, writeLen, endpoint, key);
            BufferPool.ReturnBuffer(tempPacket);
        }
Beispiel #5
0
        private void processConnectionDenied(NetcodePacketHeader header, int length, ByteArrayReaderWriter stream)
        {
            var decryptKey = serverToClientKey;
            var denyPacket = new NetcodeDenyConnectionPacket()
            {
                Header = header
            };

            if (!denyPacket.Read(stream, length, decryptKey, connectToken.ProtocolID))
            {
                return;
            }

            pendingDisconnectState = ClientState.ConnectionDenied;

            // move onto the next server
            timer           = 0.0;
            connectionTimer = 0.0;
            connectionMoveNextEndpoint();
        }
Beispiel #6
0
        // check the packet against the client's replay protection, returning true if packet was replayed, false otherwise
        private bool checkReplay(NetcodePacketHeader header, EndPoint sender)
        {
            var cryptIdx = encryptionManager.FindEncryptionMapping(sender, time);

            if (cryptIdx == -1)
            {
                log("Replay protection failed to find encryption mapping", NetcodeLogLevel.Debug);
                return(true);
            }

            var clientIndex = encryptionManager.GetClientID(cryptIdx);
            var client      = clientSlots[clientIndex];

            if (client == null)
            {
                log("Replay protection failed to find client", NetcodeLogLevel.Debug);
                return(true);
            }

            return(client.replayProtection.AlreadyReceived(header.SequenceNumber));
        }
Beispiel #7
0
        // process an incoming payload
        private void processConnectionPayload(ByteArrayReaderWriter reader, NetcodePacketHeader header, int size, EndPoint sender)
        {
            if (checkReplay(header, sender))
            {
                return;
            }

            // encryption mapping was not registered, so don't bother
            int cryptIdx = encryptionManager.FindEncryptionMapping(sender, time);

            if (cryptIdx == -1)
            {
                log("No crytpo key for sender", NetcodeLogLevel.Debug);
                return;
            }

            // grab the decryption key and decrypt the packet
            var decryptKey = encryptionManager.GetReceiveKey(cryptIdx);

            var payloadPacket = new NetcodePayloadPacket()
            {
                Header = header
            };

            if (!payloadPacket.Read(reader, size - (int)reader.ReadPosition, decryptKey, protocolID))
            {
                return;
            }

            var clientIndex = encryptionManager.GetClientID(cryptIdx);
            var client      = clientSlots[clientIndex];

            // trigger callback
            if (OnClientMessageReceived != null)
            {
                OnClientMessageReceived(client, payloadPacket.Payload, payloadPacket.Length);
            }

            payloadPacket.Release();
        }
Beispiel #8
0
        // process a received datagram
        private void processDatagram(byte[] payload, int size, EndPoint sender)
        {
            using (var reader = ByteArrayReaderWriter.Get(payload))
            {
                NetcodePacketHeader packetHeader = new NetcodePacketHeader();
                packetHeader.Read(reader);

                if (packetHeader.PacketType == NetcodePacketType.ConnectionRequest)
                {
                    if (!debugIgnoreConnectionRequest)
                    {
                        processConnectionRequest(reader, size, sender);
                    }
                }
                else
                {
                    switch (packetHeader.PacketType)
                    {
                    case NetcodePacketType.ChallengeResponse:
                        if (!debugIgnoreChallengeResponse)
                        {
                            processConnectionResponse(reader, packetHeader, size, sender);
                        }
                        break;

                    case NetcodePacketType.ConnectionKeepAlive:
                        processConnectionKeepAlive(reader, packetHeader, size, sender);
                        break;

                    case NetcodePacketType.ConnectionPayload:
                        processConnectionPayload(reader, packetHeader, size, sender);
                        break;

                    case NetcodePacketType.ConnectionDisconnect:
                        processConnectionDisconnect(reader, packetHeader, size, sender);
                        break;
                    }
                }
            }
        }
Beispiel #9
0
        private void processDatagram(Datagram datagram)
        {
            if (!MiscUtils.AddressEqual(datagram.sender, currentServerEndpoint))
            {
                return;
            }

            using (var reader = ByteArrayReaderWriter.Get(datagram.payload))
            {
                NetcodePacketHeader packetHeader = new NetcodePacketHeader();
                packetHeader.Read(reader);

                int length = datagram.payloadSize - (int)reader.ReadPosition;

                switch (packetHeader.PacketType)
                {
                case NetcodePacketType.ConnectionChallenge:
                    processChallengePacket(packetHeader, length, reader);
                    break;

                case NetcodePacketType.ConnectionDenied:
                    processConnectionDenied(packetHeader, length, reader);
                    break;

                case NetcodePacketType.ConnectionKeepAlive:
                    processConnectionKeepAlive(packetHeader, length, reader);
                    break;

                case NetcodePacketType.ConnectionPayload:
                    processConnectionPayload(packetHeader, length, reader);
                    break;

                case NetcodePacketType.ConnectionDisconnect:
                    processConnectionDisconnect(packetHeader, length, reader);
                    break;
                }
            }
        }
Beispiel #10
0
        private void processChallengePacket(NetcodePacketHeader header, int length, ByteArrayReaderWriter stream)
        {
            var decryptKey      = serverToClientKey;
            var challengePacket = new NetcodeConnectionChallengeResponsePacket()
            {
                Header = header
            };

            if (!challengePacket.Read(stream, length, decryptKey, connectToken.ProtocolID))
            {
                return;
            }

            if (state == ClientState.SendingConnectionRequest)
            {
                this.challengeResponse = challengePacket;
                this.challengeResponse.Header.PacketType = NetcodePacketType.ChallengeResponse;

                // move onto sending challenge response
                timer           = 0.0;
                connectionTimer = 0.0;
                changeState(ClientState.SendingChallengeResponse);
            }
        }
Beispiel #11
0
        private void processConnectionDisconnect(NetcodePacketHeader header, int length, ByteArrayReaderWriter stream)
        {
            if (checkReplay(header))
            {
                return;
            }
            if (this.state != ClientState.Connected)
            {
                return;
            }

            var decryptKey       = serverToClientKey;
            var disconnectPacket = new NetcodeDisconnectPacket()
            {
                Header = header
            };

            if (!disconnectPacket.Read(stream, length, decryptKey, connectToken.ProtocolID))
            {
                return;
            }

            Disconnect();
        }
Beispiel #12
0
        // process an incoming connection response packet
        private void processConnectionResponse(ByteArrayReaderWriter reader, NetcodePacketHeader header, int size, EndPoint sender)
        {
            log("Got connection response", NetcodeLogLevel.Debug);

            // encryption mapping was not registered, so don't bother
            int cryptIdx = encryptionManager.FindEncryptionMapping(sender, time);

            if (cryptIdx == -1)
            {
                log("No crytpo key for sender", NetcodeLogLevel.Debug);
                return;
            }

            // grab the decryption key and decrypt the packet
            var decryptKey = encryptionManager.GetReceiveKey(cryptIdx);

            var connectionResponsePacket = new NetcodeConnectionChallengeResponsePacket()
            {
                Header = header
            };

            if (!connectionResponsePacket.Read(reader, size - (int)reader.ReadPosition, decryptKey, protocolID))
            {
                log("Failed to decrypt packet", NetcodeLogLevel.Debug);
                return;
            }

            var challengeToken = new NetcodeChallengeToken();

            if (!challengeToken.Read(connectionResponsePacket.ChallengeTokenBytes, connectionResponsePacket.ChallengeTokenSequence, challengeKey))
            {
                log("Failed to read challenge token", NetcodeLogLevel.Debug);
                connectionResponsePacket.Release();
                return;
            }

            // if a client from packet source IP / port is already connected, ignore the packet
            if (clientSlots.Any(x => x != null && x.RemoteEndpoint.Equals(sender)))
            {
                log("Client {0} already connected", NetcodeLogLevel.Debug, sender.ToString());
                return;
            }

            // if a client with the same id is already connected, ignore the packet
            if (clientSlots.Any(x => x != null && x.ClientID == challengeToken.ClientID))
            {
                log("Client ID {0} already connected", NetcodeLogLevel.Debug, challengeToken.ClientID);
                return;
            }

            // if the server is full, deny the connection
            int nextSlot = getFreeClientSlot();

            if (nextSlot == -1)
            {
                log("Server full, denying connection", NetcodeLogLevel.Info);
                denyConnection(sender, encryptionManager.GetSendKey(cryptIdx));
                return;
            }

            // assign the endpoint and client ID to a free client slot and set connected to true
            RemoteClient client = new RemoteClient(this);

            client.ClientID         = challengeToken.ClientID;
            client.RemoteEndpoint   = sender;
            client.Connected        = true;
            client.replayProtection = new NetcodeReplayProtection();

            // assign timeout to client
            client.timeoutSeconds = encryptionManager.GetTimeoutSeconds(cryptIdx);

            // assign client to a free slot
            client.ClientIndex         = (uint)nextSlot;
            this.clientSlots[nextSlot] = client;

            encryptionManager.SetClientID(cryptIdx, client.ClientIndex);

            // copy user data so application can make use of it, and set confirmed to false
            client.UserData  = challengeToken.UserData;
            client.Confirmed = false;

            client.Touch(time);

            // respond with a connection keep alive packet
            sendKeepAlive(client);
        }
Beispiel #13
0
        // process an incoming connection keep alive packet
        private void processConnectionKeepAlive(ByteArrayReaderWriter reader, NetcodePacketHeader header, int size, EndPoint sender)
        {
            if (checkReplay(header, sender))
            {
                log("Detected replay in keep-alive", NetcodeLogLevel.Debug);
                return;
            }

            // encryption mapping was not registered, so don't bother
            int cryptIdx = encryptionManager.FindEncryptionMapping(sender, time);

            if (cryptIdx == -1)
            {
                log("No crytpo key for sender", NetcodeLogLevel.Debug);
                return;
            }

            // grab the decryption key and decrypt the packet
            var decryptKey = encryptionManager.GetReceiveKey(cryptIdx);

            var keepAlivePacket = new NetcodeKeepAlivePacket()
            {
                Header = header
            };

            if (!keepAlivePacket.Read(reader, size - (int)reader.ReadPosition, decryptKey, protocolID))
            {
                log("Failed to decrypt", NetcodeLogLevel.Debug);
                return;
            }

            if (keepAlivePacket.ClientIndex >= maxSlots)
            {
                log("Invalid client index", NetcodeLogLevel.Debug);
                return;
            }

            var client = this.clientSlots[(int)keepAlivePacket.ClientIndex];

            if (client == null)
            {
                log("Failed to find client for endpoint", NetcodeLogLevel.Debug);
                return;
            }

            if (!client.RemoteEndpoint.Equals(sender))
            {
                log("Client does not match sender", NetcodeLogLevel.Debug);
                return;
            }

            if (!client.Confirmed)
            {
                // trigger callback
                if (OnClientConnected != null)
                {
                    OnClientConnected(client);
                }

                log("Client {0} connected", NetcodeLogLevel.Info, client.RemoteEndpoint);
            }

            client.Confirmed = true;

            client.Touch(time);

            int idx = encryptionManager.FindEncryptionMapping(client.RemoteEndpoint, time);

            encryptionManager.Touch(idx, client.RemoteEndpoint, time);
        }
Beispiel #14
0
        // process an incoming disconnect message
        private void processConnectionDisconnect(ByteArrayReaderWriter reader, NetcodePacketHeader header, int size, EndPoint sender)
        {
            if (checkReplay(header, sender))
            {
                return;
            }

            // encryption mapping was not registered, so don't bother
            int cryptIdx = encryptionManager.FindEncryptionMapping(sender, time);

            if (cryptIdx == -1)
            {
                log("No crytpo key for sender", NetcodeLogLevel.Debug);
                return;
            }

            var decryptKey = encryptionManager.GetReceiveKey(cryptIdx);

            var disconnectPacket = new NetcodeDisconnectPacket()
            {
                Header = header
            };

            if (!disconnectPacket.Read(reader, size - (int)reader.ReadPosition, decryptKey, protocolID))
            {
                return;
            }

            // locate the client by endpoint and free their slot
            var clientIndex = encryptionManager.GetClientID(cryptIdx);

            var client = clientSlots[clientIndex];

            if (client == null)
            {
                return;
            }

            clientSlots[clientIndex] = null;

            // remove encryption mapping
            encryptionManager.RemoveEncryptionMapping(sender, time);

            // make sure all other clients still have their encryption mappings
            foreach (RemoteClient otherClient in clientSlots)
            {
                if (otherClient == null)
                {
                    continue;
                }
                if (encryptionManager.FindEncryptionMapping(otherClient.RemoteEndpoint, time) == -1)
                {
                    log("Encryption mapping removed wrong mapping!", NetcodeLogLevel.Debug);
                }
            }

            // trigger client disconnect callback
            if (OnClientDisconnected != null)
            {
                OnClientDisconnected(client);
            }

            log("Client {0} disconnected", NetcodeLogLevel.Info, client.RemoteEndpoint);
        }
Beispiel #15
0
 private bool checkReplay(NetcodePacketHeader packetHeader)
 {
     return(replayProtection.AlreadyReceived(packetHeader.SequenceNumber));
 }