int main(int argc, char **argv) { if (argc<8) { printf("Arguments: serverIP, pathToGame, gameName, patchImmediately, localPort, serverPort, fullScan"); return 0; } RakNet::SystemAddress TCPServerAddress=RakNet::UNASSIGNED_SYSTEM_ADDRESS; RakNet::AutopatcherClient autopatcherClient; RakNet::FileListTransfer fileListTransfer; RakNet::CloudClient cloudClient; autopatcherClient.SetFileListTransferPlugin(&fileListTransfer); bool didRebalance=false; // So we only reconnect to a lower load server once, for load balancing bool fullScan = argv[7][0]=='1'; unsigned short localPort; localPort=atoi(argv[5]); unsigned short serverPort=atoi(argv[6]); RakNet::PacketizedTCP packetizedTCP; if (packetizedTCP.Start(localPort,1)==false) { printf("Failed to start TCP. Is the port already in use?"); return 1; } packetizedTCP.AttachPlugin(&autopatcherClient); packetizedTCP.AttachPlugin(&fileListTransfer); RakNet::RakPeerInterface *rakPeer; rakPeer = RakNet::RakPeerInterface::GetInstance(); RakNet::SocketDescriptor socketDescriptor(localPort,0); rakPeer->Startup(1,&socketDescriptor, 1); rakPeer->AttachPlugin(&cloudClient); DataStructures::List<RakNet::RakNetSocket2* > sockets; rakPeer->GetSockets(sockets); printf("Started on port %i\n", sockets[0]->GetBoundAddress().GetPort()); char buff[512]; strcpy(buff, argv[1]); rakPeer->Connect(buff, serverPort, 0, 0); printf("Connecting...\n"); char appDir[512]; strcpy(appDir, argv[2]); char appName[512]; strcpy(appName, argv[3]); bool patchImmediately=argc>=5 && argv[4][0]=='1'; RakNet::Packet *p; while (1) { RakNet::SystemAddress notificationAddress; notificationAddress=packetizedTCP.HasCompletedConnectionAttempt(); if (notificationAddress!=RakNet::UNASSIGNED_SYSTEM_ADDRESS) { printf("ID_CONNECTION_REQUEST_ACCEPTED\n"); TCPServerAddress=notificationAddress; } notificationAddress=packetizedTCP.HasNewIncomingConnection(); if (notificationAddress!=RakNet::UNASSIGNED_SYSTEM_ADDRESS) printf("ID_NEW_INCOMING_CONNECTION\n"); notificationAddress=packetizedTCP.HasLostConnection(); if (notificationAddress!=RakNet::UNASSIGNED_SYSTEM_ADDRESS) printf("ID_CONNECTION_LOST\n"); notificationAddress=packetizedTCP.HasFailedConnectionAttempt(); if (notificationAddress!=RakNet::UNASSIGNED_SYSTEM_ADDRESS) { printf("ID_CONNECTION_ATTEMPT_FAILED TCP\n"); autopatcherClient.SetFileListTransferPlugin(0); autopatcherClient.Clear(); packetizedTCP.Stop(); rakPeer->Shutdown(500,0); RakNet::RakPeerInterface::DestroyInstance(rakPeer); return 0; } p=packetizedTCP.Receive(); while (p) { if (p->data[0]==ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR) { char buff[256]; RakNet::BitStream temp(p->data, p->length, false); temp.IgnoreBits(8); RakNet::StringCompressor::Instance()->DecodeString(buff, 256, &temp); printf("ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR\n"); printf("%s\n", buff); autopatcherClient.SetFileListTransferPlugin(0); autopatcherClient.Clear(); packetizedTCP.Stop(); rakPeer->Shutdown(500,0); RakNet::RakPeerInterface::DestroyInstance(rakPeer); return 0; } else if (p->data[0]==ID_AUTOPATCHER_CANNOT_DOWNLOAD_ORIGINAL_UNMODIFIED_FILES) { printf("ID_AUTOPATCHER_CANNOT_DOWNLOAD_ORIGINAL_UNMODIFIED_FILES\n"); autopatcherClient.SetFileListTransferPlugin(0); autopatcherClient.Clear(); packetizedTCP.Stop(); rakPeer->Shutdown(500,0); RakNet::RakPeerInterface::DestroyInstance(rakPeer); return 0; } else if (p->data[0]==ID_AUTOPATCHER_FINISHED) { printf("ID_AUTOPATCHER_FINISHED with server time %f\n", autopatcherClient.GetServerDate()); double srvDate=autopatcherClient.GetServerDate(); FILE *fp = fopen("srvDate", "wb"); fwrite(&srvDate,sizeof(double),1,fp); fclose(fp); autopatcherClient.SetFileListTransferPlugin(0); autopatcherClient.Clear(); packetizedTCP.Stop(); rakPeer->Shutdown(500,0); RakNet::RakPeerInterface::DestroyInstance(rakPeer); return 0; } else if (p->data[0]==ID_AUTOPATCHER_RESTART_APPLICATION) { printf("ID_AUTOPATCHER_RESTART_APPLICATION"); autopatcherClient.SetFileListTransferPlugin(0); autopatcherClient.Clear(); packetizedTCP.Stop(); rakPeer->Shutdown(500,0); RakNet::RakPeerInterface::DestroyInstance(rakPeer); return 0; } // Launch \"AutopatcherClientRestarter.exe autopatcherRestart.txt\"\nQuit this application immediately after to unlock files.\n"); packetizedTCP.DeallocatePacket(p); p=packetizedTCP.Receive(); } p=rakPeer->Receive(); while (p) { if (p->data[0]==ID_CONNECTION_REQUEST_ACCEPTED) { // UploadInstanceToCloud(&cloudClient, p->guid); // GetClientSubscription(&cloudClient, p->guid); GetServers(&cloudClient, p->guid); break; } else if (p->data[0]==ID_CONNECTION_ATTEMPT_FAILED) { printf("ID_CONNECTION_ATTEMPT_FAILED UDP\n"); autopatcherClient.SetFileListTransferPlugin(0); autopatcherClient.Clear(); packetizedTCP.Stop(); rakPeer->Shutdown(500,0); RakNet::RakPeerInterface::DestroyInstance(rakPeer); return 0; } else if (p->data[0]==ID_CLOUD_GET_RESPONSE) { RakNet::CloudQueryResult cloudQueryResult; cloudClient.OnGetReponse(&cloudQueryResult, p); unsigned int rowIndex; const bool wasCallToGetServers=cloudQueryResult.cloudQuery.keys[0].primaryKey=="CloudConnCount"; printf("\n"); if (wasCallToGetServers) printf("Downloaded server list. %i servers.\n", cloudQueryResult.rowsReturned.Size()); unsigned short connectionsOnOurServer=65535; unsigned short lowestConnectionsServer=65535; RakNet::SystemAddress lowestConnectionAddress; for (rowIndex=0; rowIndex < cloudQueryResult.rowsReturned.Size(); rowIndex++) { RakNet::CloudQueryRow *row = cloudQueryResult.rowsReturned[rowIndex]; if (wasCallToGetServers) { unsigned short connCount; RakNet::BitStream bsIn(row->data, row->length, false); bsIn.Read(connCount); printf("%i. Server found at %s with %i connections\n", rowIndex+1, row->serverSystemAddress.ToString(true), connCount); unsigned short connectionsExcludingOurselves; if (row->serverGUID==p->guid) connectionsExcludingOurselves=connCount-1; else connectionsExcludingOurselves=connCount; // Find the lowest load server (optional) if (p->guid==row->serverGUID) { connectionsOnOurServer=connectionsExcludingOurselves; } else if (connectionsExcludingOurselves < lowestConnectionsServer) { lowestConnectionsServer=connectionsExcludingOurselves; lowestConnectionAddress=row->serverSystemAddress; } } } // Do load balancing by reconnecting to lowest load server (optional) if (didRebalance==false && wasCallToGetServers) { if (cloudQueryResult.rowsReturned.Size()>0 && connectionsOnOurServer>lowestConnectionsServer) { printf("Reconnecting to lower load server %s\n", lowestConnectionAddress.ToString(false)); rakPeer->CloseConnection(p->guid, true); // Wait for the thread to close, otherwise will immediately get back ID_CONNECTION_ATTEMPT_FAILED because no free outgoing connection slots // Alternatively, just call Startup() with 2 slots instead of 1 RakSleep(500); rakPeer->Connect(lowestConnectionAddress.ToString(false), lowestConnectionAddress.GetPort(), 0, 0); // TCP Connect to new IP address packetizedTCP.Connect(lowestConnectionAddress.ToString(false),serverPort,false); } else { // TCP Connect to original IP address packetizedTCP.Connect(buff,serverPort,false); } didRebalance=true; } cloudClient.DeallocateWithDefaultAllocator(&cloudQueryResult); } rakPeer->DeallocatePacket(p); p=rakPeer->Receive(); } if (TCPServerAddress!=RakNet::UNASSIGNED_SYSTEM_ADDRESS && patchImmediately==true) { patchImmediately=false; char restartFile[512]; strcpy(restartFile, appDir); strcat(restartFile, "/autopatcherRestart.txt"); double lastUpdateDate; if (fullScan==false) { FILE *fp = fopen("srvDate", "rb"); if (fp) { fread(&lastUpdateDate, sizeof(lastUpdateDate), 1, fp); fclose(fp); } else lastUpdateDate=0; } else lastUpdateDate=0; if (autopatcherClient.PatchApplication(appName, appDir, lastUpdateDate, TCPServerAddress, &transferCallback, restartFile, argv[0])) { printf("Patching process starting.\n"); } else { printf("Failed to start patching.\n"); autopatcherClient.SetFileListTransferPlugin(0); autopatcherClient.Clear(); packetizedTCP.Stop(); rakPeer->Shutdown(500,0); RakNet::RakPeerInterface::DestroyInstance(rakPeer); return 0; } } RakSleep(30); } // Dereference so the destructor doesn't crash autopatcherClient.SetFileListTransferPlugin(0); autopatcherClient.Clear(); packetizedTCP.Stop(); rakPeer->Shutdown(500,0); RakNet::RakPeerInterface::DestroyInstance(rakPeer); return 1; }