AutopatcherClientTest.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. // Common includes
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include "Kbhit.h"
  14. #include "GetTime.h"
  15. #include "RakPeerInterface.h"
  16. #include "MessageIdentifiers.h"
  17. #include "BitStream.h"
  18. #include "StringCompressor.h"
  19. #include "PacketizedTCP.h"
  20. // Client only includes
  21. #include "FileListTransferCBInterface.h"
  22. #include "FileListTransfer.h"
  23. #include "AutopatcherClient.h"
  24. #include "AutopatcherPatchContext.h"
  25. #include "Gets.h"
  26. #include "RakSleep.h"
  27. char WORKING_DIRECTORY[MAX_PATH];
  28. char PATH_TO_XDELTA_EXE[MAX_PATH];
  29. class TestCB : public RakNet::AutopatcherClientCBInterface
  30. {
  31. public:
  32. virtual bool OnFile(OnFileStruct *onFileStruct)
  33. {
  34. if (onFileStruct->context.op==PC_HASH_1_WITH_PATCH || onFileStruct->context.op==PC_HASH_2_WITH_PATCH)
  35. printf("Patched: ");
  36. else if (onFileStruct->context.op==PC_WRITE_FILE)
  37. printf("Written: ");
  38. else if (onFileStruct->context.op==PC_ERROR_FILE_WRITE_FAILURE)
  39. printf("Write Failure: ");
  40. else if (onFileStruct->context.op==PC_ERROR_PATCH_TARGET_MISSING)
  41. printf("Patch target missing: ");
  42. else if (onFileStruct->context.op==PC_ERROR_PATCH_APPLICATION_FAILURE)
  43. printf("Patch process failure: ");
  44. else if (onFileStruct->context.op==PC_ERROR_PATCH_RESULT_CHECKSUM_FAILURE)
  45. printf("Patch checksum failure: ");
  46. else if (onFileStruct->context.op==PC_NOTICE_WILL_COPY_ON_RESTART)
  47. printf("Copy pending restart: ");
  48. else if (onFileStruct->context.op==PC_NOTICE_FILE_DOWNLOADED)
  49. printf("Downloaded: ");
  50. else if (onFileStruct->context.op==PC_NOTICE_FILE_DOWNLOADED_PATCH)
  51. printf("Downloaded Patch: ");
  52. else
  53. RakAssert(0);
  54. printf("%i. (100%%) %i/%i %s %ib / %ib\n", onFileStruct->setID, onFileStruct->fileIndex+1, onFileStruct->numberOfFilesInThisSet,
  55. onFileStruct->fileName, onFileStruct->byteLengthOfThisFile,
  56. onFileStruct->byteLengthOfThisSet);
  57. // Return false for the file data to be deallocated automatically
  58. return false;
  59. }
  60. virtual void OnFileProgress(FileProgressStruct *fps)
  61. {
  62. printf("Downloading: %i. (%i%%) %i/%i %s %ib/%ib %ib/%ib total\n", fps->onFileStruct->setID,
  63. (int) (100.0*(double)fps->onFileStruct->bytesDownloadedForThisFile/(double)fps->onFileStruct->byteLengthOfThisFile),
  64. fps->onFileStruct->fileIndex+1, fps->onFileStruct->numberOfFilesInThisSet, fps->onFileStruct->fileName,
  65. fps->onFileStruct->bytesDownloadedForThisFile,
  66. fps->onFileStruct->byteLengthOfThisFile,
  67. fps->onFileStruct->bytesDownloadedForThisSet,
  68. fps->onFileStruct->byteLengthOfThisSet
  69. );
  70. }
  71. virtual PatchContext ApplyPatchBase(const char *oldFilePath, char **newFileContents, unsigned int *newFileSize, char *patchContents, unsigned int patchSize, uint32_t patchAlgorithm)
  72. {
  73. if (patchAlgorithm==0)
  74. {
  75. return ApplyPatchBSDiff(oldFilePath, newFileContents, newFileSize, patchContents, patchSize);
  76. }
  77. else
  78. {
  79. char buff[128];
  80. RakNet::TimeUS time = RakNet::GetTimeUS();
  81. #if defined(_WIN32)
  82. sprintf(buff, "%I64u", time);
  83. #else
  84. sprintf(buff, "%llu", (long long unsigned int) time);
  85. #endif
  86. char pathToPatch1[MAX_PATH], pathToPatch2[MAX_PATH];
  87. sprintf(pathToPatch1, "%s/patchClient_%s.tmp", WORKING_DIRECTORY, buff);
  88. FILE *fpPatch = fopen(pathToPatch1, "wb");
  89. if (fpPatch==0)
  90. return PC_ERROR_PATCH_TARGET_MISSING;
  91. fwrite(patchContents, 1, patchSize, fpPatch);
  92. fclose(fpPatch);
  93. // Invoke xdelta
  94. // See https://code.google.com/p/xdelta/wiki/CommandLineSyntax
  95. char commandLine[512];
  96. _snprintf(commandLine, sizeof(commandLine)-1, "-d -f -s %s patchClient_%s.tmp newFile_%s.tmp", oldFilePath, buff, buff);
  97. commandLine[511]=0;
  98. SHELLEXECUTEINFO shellExecuteInfo;
  99. shellExecuteInfo.cbSize = sizeof(SHELLEXECUTEINFO);
  100. shellExecuteInfo.fMask = SEE_MASK_NOASYNC | SEE_MASK_NO_CONSOLE;
  101. shellExecuteInfo.hwnd = NULL;
  102. shellExecuteInfo.lpVerb = "open";
  103. shellExecuteInfo.lpFile = PATH_TO_XDELTA_EXE;
  104. shellExecuteInfo.lpParameters = commandLine;
  105. shellExecuteInfo.lpDirectory = WORKING_DIRECTORY;
  106. shellExecuteInfo.nShow = SW_SHOWNORMAL;
  107. shellExecuteInfo.hInstApp = NULL;
  108. ShellExecuteEx(&shellExecuteInfo);
  109. // ShellExecute(NULL, "open", PATH_TO_XDELTA_EXE, commandLine, WORKING_DIRECTORY, SW_SHOWNORMAL);
  110. sprintf(pathToPatch2, "%s/newFile_%s.tmp", WORKING_DIRECTORY, buff);
  111. fpPatch = fopen(pathToPatch2, "r+b");
  112. RakNet::TimeUS stopWaiting = time + 60000000;
  113. while (fpPatch==0 && RakNet::GetTimeUS() < stopWaiting)
  114. {
  115. RakSleep(1000);
  116. fpPatch = fopen(pathToPatch2, "r+b");
  117. }
  118. if (fpPatch==0)
  119. {
  120. printf("\nERROR: Could not open %s.\nerr=%i (%s)\narguments=%s\n", pathToPatch2, errno, strerror(errno), commandLine);
  121. return PC_ERROR_PATCH_TARGET_MISSING;
  122. }
  123. fseek(fpPatch, 0, SEEK_END);
  124. *newFileSize = ftell(fpPatch);
  125. fseek(fpPatch, 0, SEEK_SET);
  126. *newFileContents = (char*) rakMalloc_Ex(*newFileSize, _FILE_AND_LINE_);
  127. fread(*newFileContents, 1, *newFileSize, fpPatch);
  128. fclose(fpPatch);
  129. int unlinkRes1 = _unlink(pathToPatch1);
  130. int unlinkRes2 = _unlink(pathToPatch2);
  131. while ((unlinkRes1!=0 || unlinkRes2!=0) && RakNet::GetTimeUS() < stopWaiting)
  132. {
  133. RakSleep(1000);
  134. if (unlinkRes1!=0)
  135. unlinkRes1 = _unlink(pathToPatch1);
  136. if (unlinkRes2!=0)
  137. unlinkRes2 = _unlink(pathToPatch2);
  138. }
  139. if (unlinkRes1!=0)
  140. printf("\nWARNING: unlink %s failed.\nerr=%i (%s)\n", pathToPatch1, errno, strerror(errno));
  141. if (unlinkRes2!=0)
  142. printf("\nWARNING: unlink %s failed.\nerr=%i (%s)\n", pathToPatch2, errno, strerror(errno));
  143. return PC_WRITE_FILE;
  144. }
  145. }
  146. } transferCallback;
  147. #define USE_TCP
  148. int main(int argc, char **argv)
  149. {
  150. printf("A simple client interface for the advanced autopatcher.\n");
  151. printf("Use DirectoryDeltaTransfer for a simpler version of an autopatcher.\n");
  152. printf("Difficulty: Intermediate\n\n");
  153. printf("Client starting...");
  154. RakNet::SystemAddress serverAddress=RakNet::UNASSIGNED_SYSTEM_ADDRESS;
  155. RakNet::AutopatcherClient autopatcherClient;
  156. RakNet::FileListTransfer fileListTransfer;
  157. autopatcherClient.SetFileListTransferPlugin(&fileListTransfer);
  158. unsigned short localPort=0;
  159. if (argc>=6)
  160. {
  161. localPort=atoi(argv[5]);
  162. }
  163. #ifdef USE_TCP
  164. RakNet::PacketizedTCP packetizedTCP;
  165. if (packetizedTCP.Start(localPort,1)==false)
  166. {
  167. printf("Failed to start TCP. Is the port already in use?");
  168. return 1;
  169. }
  170. packetizedTCP.AttachPlugin(&autopatcherClient);
  171. packetizedTCP.AttachPlugin(&fileListTransfer);
  172. #else
  173. RakNet::RakPeerInterface *rakPeer;
  174. rakPeer = RakNet::RakPeerInterface::GetInstance();
  175. RakNet::SocketDescriptor socketDescriptor(localPort,0);
  176. rakPeer->Startup(1,&socketDescriptor, 1);
  177. // Plugin will send us downloading progress notifications if a file is split to fit under the MTU 10 or more times
  178. rakPeer->SetSplitMessageProgressInterval(10);
  179. rakPeer->AttachPlugin(&autopatcherClient);
  180. rakPeer->AttachPlugin(&fileListTransfer);
  181. #endif
  182. printf("started\n");
  183. char buff[512];
  184. if (argc<2)
  185. {
  186. printf("Enter server IP: ");
  187. Gets(buff,sizeof(buff));
  188. if (buff[0]==0)
  189. //strcpy(buff, "natpunch.jenkinssoftware.com");
  190. strcpy(buff, "127.0.0.1");
  191. }
  192. else
  193. strcpy(buff, argv[1]);
  194. #ifdef USE_TCP
  195. packetizedTCP.Connect(buff,60000,false);
  196. #else
  197. rakPeer->Connect(buff, 60000, 0, 0);
  198. #endif
  199. printf("Connecting...\n");
  200. char appDir[512];
  201. if (argc<3)
  202. {
  203. printf("Enter application directory: ");
  204. Gets(appDir,sizeof(appDir));
  205. if (appDir[0]==0)
  206. {
  207. strcpy(appDir, "D:/temp2");
  208. }
  209. }
  210. else
  211. strcpy(appDir, argv[2]);
  212. char appName[512];
  213. if (argc<4)
  214. {
  215. printf("Enter application name: ");
  216. Gets(appName,sizeof(appName));
  217. if (appName[0]==0)
  218. strcpy(appName, "TestApp");
  219. }
  220. else
  221. strcpy(appName, argv[3]);
  222. bool patchImmediately=argc>=5 && argv[4][0]=='1';
  223. if (patchImmediately==false)
  224. {
  225. printf("Optional: Enter path to xdelta exe: ");
  226. Gets(PATH_TO_XDELTA_EXE, sizeof(PATH_TO_XDELTA_EXE));
  227. // https://code.google.com/p/xdelta/downloads/list
  228. if (PATH_TO_XDELTA_EXE[0]==0)
  229. strcpy(PATH_TO_XDELTA_EXE, "c:/xdelta3-3.0.6-win32.exe");
  230. if (PATH_TO_XDELTA_EXE[0])
  231. {
  232. printf("Enter working directory to store temporary files: ");
  233. Gets(WORKING_DIRECTORY, sizeof(WORKING_DIRECTORY));
  234. if (WORKING_DIRECTORY[0]==0)
  235. GetTempPath(MAX_PATH, WORKING_DIRECTORY);
  236. if (WORKING_DIRECTORY[strlen(WORKING_DIRECTORY)-1]=='\\' || WORKING_DIRECTORY[strlen(WORKING_DIRECTORY)-1]=='/')
  237. WORKING_DIRECTORY[strlen(WORKING_DIRECTORY)-1]=0;
  238. }
  239. printf("Hit 'q' to quit, 'p' to patch, 'f' to full scan. 'c' to cancel the patch. 'r' to reconnect. 'd' to disconnect.\n");
  240. }
  241. else
  242. printf("Hit 'q' to quit, 'c' to cancel the patch.\n");
  243. char ch;
  244. RakNet::Packet *p;
  245. while (1)
  246. {
  247. #ifdef USE_TCP
  248. RakNet::SystemAddress notificationAddress;
  249. notificationAddress=packetizedTCP.HasCompletedConnectionAttempt();
  250. if (notificationAddress!=RakNet::UNASSIGNED_SYSTEM_ADDRESS)
  251. {
  252. printf("ID_CONNECTION_REQUEST_ACCEPTED\n");
  253. serverAddress=notificationAddress;
  254. }
  255. notificationAddress=packetizedTCP.HasNewIncomingConnection();
  256. if (notificationAddress!=RakNet::UNASSIGNED_SYSTEM_ADDRESS)
  257. printf("ID_NEW_INCOMING_CONNECTION\n");
  258. notificationAddress=packetizedTCP.HasLostConnection();
  259. if (notificationAddress!=RakNet::UNASSIGNED_SYSTEM_ADDRESS)
  260. printf("ID_CONNECTION_LOST\n");
  261. p=packetizedTCP.Receive();
  262. while (p)
  263. {
  264. if (p->data[0]==ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR)
  265. {
  266. char buff[256];
  267. RakNet::BitStream temp(p->data, p->length, false);
  268. temp.IgnoreBits(8);
  269. RakNet::StringCompressor::Instance()->DecodeString(buff, 256, &temp);
  270. printf("ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR\n");
  271. printf("%s\n", buff);
  272. }
  273. else if (p->data[0]==ID_AUTOPATCHER_CANNOT_DOWNLOAD_ORIGINAL_UNMODIFIED_FILES)
  274. {
  275. printf("ID_AUTOPATCHER_CANNOT_DOWNLOAD_ORIGINAL_UNMODIFIED_FILES\n");
  276. }
  277. else if (p->data[0]==ID_AUTOPATCHER_FINISHED)
  278. {
  279. printf("ID_AUTOPATCHER_FINISHED with server time %f\n", autopatcherClient.GetServerDate());
  280. double srvDate=autopatcherClient.GetServerDate();
  281. FILE *fp = fopen("srvDate", "wb");
  282. fwrite(&srvDate,sizeof(double),1,fp);
  283. fclose(fp);
  284. }
  285. else if (p->data[0]==ID_AUTOPATCHER_RESTART_APPLICATION)
  286. printf("Launch \"AutopatcherClientRestarter.exe autopatcherRestart.txt\"\nQuit this application immediately after to unlock files.\n");
  287. packetizedTCP.DeallocatePacket(p);
  288. p=packetizedTCP.Receive();
  289. }
  290. #else
  291. p=rakPeer->Receive();
  292. while (p)
  293. {
  294. if (p->data[0]==ID_DISCONNECTION_NOTIFICATION)
  295. printf("ID_DISCONNECTION_NOTIFICATION\n");
  296. else if (p->data[0]==ID_CONNECTION_LOST)
  297. printf("ID_CONNECTION_LOST\n");
  298. else if (p->data[0]==ID_CONNECTION_REQUEST_ACCEPTED)
  299. {
  300. printf("ID_CONNECTION_REQUEST_ACCEPTED\n");
  301. serverAddress=p->systemAddress;
  302. }
  303. else if (p->data[0]==ID_CONNECTION_ATTEMPT_FAILED)
  304. printf("ID_CONNECTION_ATTEMPT_FAILED\n");
  305. else if (p->data[0]==ID_NO_FREE_INCOMING_CONNECTIONS)
  306. printf("ID_NO_FREE_INCOMING_CONNECTIONS\n");
  307. else if (p->data[0]==ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR)
  308. {
  309. char buff[256];
  310. RakNet::BitStream temp(p->data, p->length, false);
  311. temp.IgnoreBits(8);
  312. RakNet::StringCompressor::Instance()->DecodeString(buff, 256, &temp);
  313. printf("ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR\n");
  314. printf("%s\n", buff);
  315. }
  316. else if (p->data[0]==ID_AUTOPATCHER_CANNOT_DOWNLOAD_ORIGINAL_UNMODIFIED_FILES)
  317. {
  318. printf("ID_AUTOPATCHER_CANNOT_DOWNLOAD_ORIGINAL_UNMODIFIED_FILES\n");
  319. }
  320. else if (p->data[0]==ID_AUTOPATCHER_FINISHED)
  321. {
  322. printf("ID_AUTOPATCHER_FINISHED with server time %f\n", autopatcherClient.GetServerDate());
  323. double srvDate=autopatcherClient.GetServerDate();
  324. FILE *fp = fopen("srvDate", "wb");
  325. fwrite(&srvDate,sizeof(double),1,fp);
  326. fclose(fp);
  327. }
  328. else if (p->data[0]==ID_AUTOPATCHER_RESTART_APPLICATION)
  329. printf("Launch \"AutopatcherClientRestarter.exe autopatcherRestart.txt\"\nQuit this application immediately after to unlock files.\n");
  330. rakPeer->DeallocatePacket(p);
  331. p=rakPeer->Receive();
  332. }
  333. #endif
  334. if (kbhit())
  335. ch=getch();
  336. else
  337. ch=0;
  338. if (ch=='q')
  339. break;
  340. else if (ch=='r')
  341. {
  342. #ifdef USE_TCP
  343. packetizedTCP.Connect(buff,60000,false);
  344. #else
  345. rakPeer->Connect(buff, 60000, 0, 0);
  346. #endif
  347. }
  348. else if (ch=='d')
  349. {
  350. #ifdef USE_TCP
  351. packetizedTCP.CloseConnection(serverAddress);
  352. #else
  353. rakPeer->CloseConnection(serverAddress, true);
  354. #endif
  355. }
  356. else if (ch=='p' || (serverAddress!=RakNet::UNASSIGNED_SYSTEM_ADDRESS && patchImmediately==true) || ch=='f')
  357. {
  358. patchImmediately=false;
  359. char restartFile[512];
  360. strcpy(restartFile, appDir);
  361. strcat(restartFile, "/autopatcherRestart.txt");
  362. double lastUpdateDate;
  363. if (ch=='f')
  364. {
  365. lastUpdateDate=0;
  366. }
  367. else
  368. {
  369. FILE *fp = fopen("srvDate", "rb");
  370. if (fp)
  371. {
  372. fread(&lastUpdateDate, sizeof(lastUpdateDate), 1, fp);
  373. fclose(fp);
  374. }
  375. else
  376. lastUpdateDate=0;
  377. }
  378. if (autopatcherClient.PatchApplication(appName, appDir, lastUpdateDate, serverAddress, &transferCallback, restartFile, argv[0]))
  379. {
  380. printf("Patching process starting.\n");
  381. }
  382. else
  383. {
  384. printf("Failed to start patching.\n");
  385. }
  386. }
  387. else if (ch=='c')
  388. {
  389. autopatcherClient.Clear();
  390. printf("Autopatcher cleared.\n");
  391. }
  392. RakSleep(30);
  393. }
  394. // Dereference so the destructor doesn't crash
  395. autopatcherClient.SetFileListTransferPlugin(0);
  396. #ifdef USE_TCP
  397. packetizedTCP.Stop();
  398. #else
  399. rakPeer->Shutdown(500,0);
  400. RakNet::RakPeerInterface::DestroyInstance(rakPeer);
  401. #endif
  402. return 1;
  403. }
粤ICP备19079148号