// ---------------------------------------------------------------------- // RakNet version 1.405 // ClientFileVerification.cpp // Created by Rakkar Software (rakkar@rakkarsoftware.com) December 1, 2003 // Shows how to verify that a file on the client matches a file on the server. // ---------------------------------------------------------------------- #include "Multiplayer.h" #include "RakClientInterface.h" #include "RakServerInterface.h" #include "RakNetworkFactory.h" #include "SHA1.h" #include "BitStream.h" #include "FileVerifier.h" using namespace RakNet; #include #ifdef WIN32 #include #else #include "../Unix/kbhit.h" #endif // RPC callback prototype void VerifyFiles(RPCParameters *rpcParameters); // Derive a new class to handle unknown files class TestFileVerifier : public FileVerifier { bool OnUnknownFile(char *filename) { printf("Client has the file %s which we don't know about.\nPress 'y' to allow the file, 'n' to fail.\n",filename); char buff[256]; if(gets(buff)&&(buff[0]=='y')) return true; else return false; } } fileVerifier; RakClientInterface *rakClient; RakServerInterface *rakServer; // We derive from the Multiplayer class to check the files on newly connected clients template class FileVerificationMultiplayer : public Multiplayer { public: void ReceiveNewIncomingConnection(Packet *packet, InterfaceType *interfaceType) { // The server got a new client. Use RPC to call VerifyFiles on the client. // We do not pass any data along with this call, send the call reliably, and only to the player that just connected. interfaceType->RPC("VerifyFiles", 0, 0, HIGH_PRIORITY, RELIABLE_ORDERED, 0, packet->playerId, false, false, UNASSIGNED_NETWORK_ID,0); } }; FileVerificationMultiplayer rakServerMultiplayer; Multiplayer rakClientMultiplayer; // C callback to handle the remote procedure call that verifies the file on the client, and compares the value generated by the client // To the value generated by the server. void VerifyFiles(RPCParameters *rpcParameters) { if (rpcParameters->sender==rakClient->GetServerID()) { // Called from the server. Serialize our validation data and send it to the server. // Write the output to a bitstream BitStream myBitStream; fileVerifier.Serialize(&myBitStream); // Call this same function on the server with the SHA1Code we are returning. This function will then run the block below. rakClient->RPC("VerifyFiles", &myBitStream, HIGH_PRIORITY, RELIABLE, 0, false, UNASSIGNED_NETWORK_ID,0); } else { // Called by the client. Get an SHA1 code from the same files the client used. We could also have compared the code against a precalculated value if the // Server doesn't have the files the client used char *output; BitStream inputBS(rpcParameters->input, BITS_TO_BYTES(rpcParameters->numberOfBitsOfData), false); output=fileVerifier.DeserializeAndValidate(&inputBS); if (output==0) printf("Client file verification succeeded\n"); else printf("Client file verification failed on %s\n", output); } } // Gets an SHA1 code for the files listed here void ValidateFiles(void) { fileVerifier.AddFileForVerification("ClientFileVerification.txt", true); fileVerifier.AddFileForVerification("Client File Verification.dsp", true); fileVerifier.AddFileForVerification("Client File Verification.vcproj", true); fileVerifier.AddFileForVerification("ClientFileVerification.cpp", true); fileVerifier.AddFileForVerification("FileVerifier.cpp", true); fileVerifier.AddFileForVerification("FileVerifier.h", true); // This should generate a warning message: fileVerifier.AddFileForVerification("blah.txt", true); } int main(void) { char serverIP[30]; rakClient=RakNetworkFactory::GetRakClientInterface(); rakServer=RakNetworkFactory::GetRakServerInterface(); REGISTER_STATIC_RPC(rakServer, VerifyFiles); REGISTER_STATIC_RPC(rakClient, VerifyFiles); char ch; char buff[256]; printf("This sample demonstrates the FileVerifier class.\n"); printf("The class takes a set of files, performs a hash on these files\n"); printf("And returns if they are different or not. The class itself is simple but\n"); printf("This sample also shows how to use remote procedure calls\n"); printf("Difficulty: Intermediate\n\n"); printf("Hit [enter] to begin CRC calculations.\n"); gets(buff); printf("Calculating CRCs...\n"); // Validate files in the debug directory ValidateFiles(); printf("Done.\n"); printf("Hit 'c' to run as a client. Hit 's' to run as a server. Hit 'q' to quit\n"); while (1) { gets(buff); ch = buff[0]; if (ch=='c') { // Run as a client. If you don't have another machine, just run 2 instances of this program and use "127.0.0.1" puts ("Enter server IP\n"); gets(serverIP); if (serverIP[0]==0) strcpy(serverIP, "127.0.0.1"); rakClient->Connect(serverIP, 2000, 2100, 0, 30); printf("Connecting client\n"); break; } else if (ch=='s') { // Run as a server. rakServer->Start(32, 0, 30, 2000); printf("Server started\n"); break; } else if (ch=='q') return 0; else { printf("Bad input. Enter 'c' 's' or 'q'.\n"); } } printf("Entering main game loop. Press any key to quit.\n"); while (!kbhit()) { // Your main game loop. rakServerMultiplayer.ProcessPackets(rakServer); rakClientMultiplayer.ProcessPackets(rakClient); } // Shutdown stuff. It's ok to call disconnect on the server if we are a client and vice-versa rakServer->Disconnect(0); rakClient->Disconnect(0); return 0; }