// send a keep-alive packet to the client private void sendKeepAlive(RemoteClient client) { var packet = new NetcodeKeepAlivePacket() { ClientIndex = client.ClientIndex, MaxSlots = (uint)this.maxSlots }; var cryptIdx = encryptionManager.FindEncryptionMapping(client.RemoteEndpoint, time); if (cryptIdx == -1) { return; } var cryptKey = encryptionManager.GetSendKey(cryptIdx); serializePacket(new NetcodePacketHeader() { PacketType = NetcodePacketType.ConnectionKeepAlive }, (writer) => { packet.Write(writer); }, client.RemoteEndpoint, cryptKey); }
/// <summary> /// Disconnect the remote client /// </summary> public void Disconnect(RemoteClient client) { disconnectClient(client); }
// 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); }
/// <summary> /// Send a payload to the remote client /// </summary> public void SendPayload(RemoteClient client, byte[] payload, int payloadSize) { sendPayloadToClient(client, payload, payloadSize); }