AutopatcherClient.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  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. #include "AutopatcherClient.h"
  11. #include "DirectoryDeltaTransfer.h"
  12. #include "FileList.h"
  13. #include "StringCompressor.h"
  14. #include "RakPeerInterface.h"
  15. #include "FileListTransfer.h"
  16. #include "FileListTransferCBInterface.h"
  17. #include "BitStream.h"
  18. #include "MessageIdentifiers.h"
  19. #include "AutopatcherPatchContext.h"
  20. #include "ApplyPatch.h"
  21. #include "FileOperations.h"
  22. //#include "DR_SHA1.h"
  23. #include <stdio.h>
  24. #include "FileOperations.h"
  25. #include "RakAssert.h"
  26. #include "ThreadPool.h"
  27. #ifdef _MSC_VER
  28. #pragma warning( push )
  29. #endif
  30. using namespace RakNet;
  31. #include "SuperFastHash.h"
  32. static const unsigned HASH_LENGTH=4;
  33. #define COPY_ON_RESTART_EXTENSION ".patched.tmp"
  34. // -----------------------------------------------------------------
  35. PatchContext AutopatcherClientCBInterface::ApplyPatchBase(const char *oldFilePath, char **newFileContents, unsigned int *newFileSize, char *patchContents, unsigned int patchSize, uint32_t patchAlgorithm)
  36. {
  37. return ApplyPatchBSDiff(oldFilePath, newFileContents, newFileSize, patchContents, patchSize);
  38. }
  39. PatchContext AutopatcherClientCBInterface::ApplyPatchBSDiff(const char *oldFilePath, char **newFileContents, unsigned int *newFileSize, char *patchContents, unsigned int patchSize)
  40. {
  41. FILE *fp;
  42. fp=fopen(oldFilePath, "rb");
  43. if (fp==0)
  44. return PC_ERROR_PATCH_TARGET_MISSING;
  45. fseek(fp, 0, SEEK_END);
  46. unsigned int prePatchLength = ftell(fp);
  47. fseek(fp, 0, SEEK_SET);
  48. char *prePatchFile = (char*) rakMalloc_Ex(prePatchLength, _FILE_AND_LINE_);
  49. fread(prePatchFile, prePatchLength, 1, fp);
  50. fclose(fp);
  51. bool result = ApplyPatch(prePatchFile, prePatchLength, newFileContents, newFileSize, patchContents, patchSize);
  52. rakFree_Ex(prePatchFile, _FILE_AND_LINE_);
  53. if (result==false)
  54. return PC_ERROR_PATCH_APPLICATION_FAILURE;
  55. return PC_WRITE_FILE;
  56. }
  57. // -----------------------------------------------------------------
  58. struct AutopatcherClientThreadInfo
  59. {
  60. FileListTransferCBInterface::OnFileStruct onFileStruct;
  61. char applicationDirectory[512];
  62. PatchContext result;
  63. // unsigned prePatchLength;
  64. // char *prePatchFile;
  65. // postPatchFile is passed in PC_NOTICE_WILL_COPY_ON_RESTART
  66. char *postPatchFile;
  67. unsigned postPatchLength;
  68. AutopatcherClientCBInterface *cbInterface;
  69. };
  70. // -----------------------------------------------------------------
  71. AutopatcherClientThreadInfo* AutopatcherClientWorkerThread(AutopatcherClientThreadInfo* input, bool *returnOutput, void* perThreadData)
  72. {
  73. char fullPathToDir[1024];
  74. *returnOutput=true;
  75. strcpy(fullPathToDir, input->applicationDirectory);
  76. strcat(fullPathToDir, input->onFileStruct.fileName);
  77. if (input->onFileStruct.context.op==PC_WRITE_FILE)
  78. {
  79. if (WriteFileWithDirectories(fullPathToDir, (char*)input->onFileStruct.fileData, input->onFileStruct.byteLengthOfThisFile)==false)
  80. {
  81. char newDir[1024];
  82. strcpy(newDir, fullPathToDir);
  83. strcat(newDir, COPY_ON_RESTART_EXTENSION);
  84. if (WriteFileWithDirectories(newDir, (char*)input->onFileStruct.fileData, input->onFileStruct.byteLengthOfThisFile))
  85. {
  86. input->result=PC_NOTICE_WILL_COPY_ON_RESTART;
  87. }
  88. else
  89. {
  90. input->result=PC_ERROR_FILE_WRITE_FAILURE;
  91. }
  92. }
  93. else
  94. {
  95. input->result=(PatchContext) input->onFileStruct.context.op;
  96. }
  97. }
  98. else
  99. {
  100. RakAssert(input->onFileStruct.context.op==PC_HASH_1_WITH_PATCH || input->onFileStruct.context.op==PC_HASH_2_WITH_PATCH);
  101. // CSHA1 sha1;
  102. // printf("apply patch %i bytes\n", byteLengthOfThisFile-SHA1_LENGTH);
  103. // for (int i=0; i < byteLengthOfThisFile-SHA1_LENGTH; i++)
  104. // printf("%i ", fileData[SHA1_LENGTH+i]);
  105. // printf("\n");
  106. int hashMultiplier;
  107. if (input->onFileStruct.context.op==PC_HASH_1_WITH_PATCH)
  108. hashMultiplier=1;
  109. else
  110. hashMultiplier=2; // else op==PC_HASH_2_WITH_PATCH
  111. PatchContext result = input->cbInterface->ApplyPatchBase(fullPathToDir, &input->postPatchFile, &input->postPatchLength, (char*)input->onFileStruct.fileData+HASH_LENGTH*hashMultiplier, input->onFileStruct.byteLengthOfThisFile-HASH_LENGTH*hashMultiplier, input->onFileStruct.context.flnc_extraData2);
  112. if (result == PC_ERROR_PATCH_APPLICATION_FAILURE || input->result==PC_ERROR_PATCH_TARGET_MISSING)
  113. {
  114. input->result=result;
  115. return input;
  116. }
  117. unsigned int hash = SuperFastHash(input->postPatchFile, input->postPatchLength);
  118. if (RakNet::BitStream::DoEndianSwap())
  119. RakNet::BitStream::ReverseBytesInPlace((unsigned char*) &hash, sizeof(hash));
  120. //if (memcmp(sha1.GetHash(), input->onFileStruct.fileData, HASH_LENGTH)!=0)
  121. if (memcmp(&hash, input->onFileStruct.fileData+HASH_LENGTH*(hashMultiplier-1), HASH_LENGTH)!=0)
  122. {
  123. input->result=PC_ERROR_PATCH_RESULT_CHECKSUM_FAILURE;
  124. }
  125. else
  126. {
  127. // Write postPatchFile over the existing file
  128. if (WriteFileWithDirectories(fullPathToDir, (char*)input->postPatchFile, input->postPatchLength)==false)
  129. {
  130. char newDir[1024];
  131. strcpy(newDir, fullPathToDir);
  132. strcat(newDir, COPY_ON_RESTART_EXTENSION);
  133. if (WriteFileWithDirectories(newDir, (char*)input->postPatchFile, input->postPatchLength))
  134. {
  135. input->result=PC_NOTICE_WILL_COPY_ON_RESTART;
  136. }
  137. else
  138. {
  139. input->result=PC_ERROR_FILE_WRITE_FAILURE;
  140. }
  141. }
  142. else
  143. {
  144. input->result=(PatchContext)input->onFileStruct.context.op;
  145. }
  146. }
  147. }
  148. return input;
  149. }
  150. // -----------------------------------------------------------------
  151. namespace RakNet
  152. {
  153. class AutopatcherClientCallback : public FileListTransferCBInterface
  154. {
  155. public:
  156. ThreadPool<AutopatcherClientThreadInfo*,AutopatcherClientThreadInfo*> threadPool;
  157. char applicationDirectory[512];
  158. AutopatcherClientCBInterface *onFileCallback;
  159. AutopatcherClient *client;
  160. bool downloadComplete;
  161. bool canDeleteUser;
  162. AutopatcherClientCallback(void)
  163. {
  164. threadPool.StartThreads(1,0);
  165. canDeleteUser=false;
  166. downloadComplete=false;
  167. }
  168. virtual ~AutopatcherClientCallback(void)
  169. {
  170. StopThreads();
  171. }
  172. void StopThreads(void)
  173. {
  174. threadPool.StopThreads();
  175. RakAssert(threadPool.NumThreadsWorking()==0);
  176. unsigned i;
  177. AutopatcherClientThreadInfo* info;
  178. for (i=0; i < threadPool.InputSize(); i++)
  179. {
  180. info = threadPool.GetInputAtIndex(i);
  181. // if (info->prePatchFile)
  182. // rakFree_Ex(info->prePatchFile, _FILE_AND_LINE_ );
  183. if (info->postPatchFile)
  184. rakFree_Ex(info->postPatchFile, _FILE_AND_LINE_ );
  185. if (info->onFileStruct.fileData)
  186. rakFree_Ex(info->onFileStruct.fileData, _FILE_AND_LINE_ );
  187. RakNet::OP_DELETE(info, _FILE_AND_LINE_);
  188. }
  189. threadPool.ClearInput();
  190. for (i=0; i < threadPool.OutputSize(); i++)
  191. {
  192. info = threadPool.GetOutputAtIndex(i);
  193. // if (info->prePatchFile)
  194. // rakFree_Ex(info->prePatchFile, _FILE_AND_LINE_ );
  195. if (info->postPatchFile)
  196. rakFree_Ex(info->postPatchFile, _FILE_AND_LINE_ );
  197. if (info->onFileStruct.fileData)
  198. rakFree_Ex(info->onFileStruct.fileData, _FILE_AND_LINE_ );
  199. RakNet::OP_DELETE(info, _FILE_AND_LINE_);
  200. }
  201. threadPool.ClearOutput();
  202. }
  203. // Update is run in the user thread
  204. virtual bool Update(void)
  205. {
  206. if (threadPool.HasOutputFast() && threadPool.HasOutput())
  207. {
  208. AutopatcherClientThreadInfo *threadInfo = threadPool.GetOutput();
  209. threadInfo->onFileStruct.context.op=threadInfo->result;
  210. switch (threadInfo->result)
  211. {
  212. case PC_NOTICE_WILL_COPY_ON_RESTART:
  213. {
  214. client->CopyAndRestart(threadInfo->onFileStruct.fileName);
  215. if (threadInfo->onFileStruct.context.op==PC_WRITE_FILE)
  216. {
  217. // Regular file in use but we can write the temporary file. Restart and copy it over the existing
  218. onFileCallback->OnFile(&threadInfo->onFileStruct);
  219. }
  220. else
  221. {
  222. // Regular file in use but we can write the temporary file. Restart and copy it over the existing
  223. rakFree_Ex(threadInfo->onFileStruct.fileData, _FILE_AND_LINE_ );
  224. threadInfo->onFileStruct.fileData=threadInfo->postPatchFile;
  225. onFileCallback->OnFile(&threadInfo->onFileStruct);
  226. threadInfo->onFileStruct.fileData=0;
  227. }
  228. }
  229. break;
  230. case PC_ERROR_FILE_WRITE_FAILURE:
  231. {
  232. if (threadInfo->onFileStruct.context.op==PC_WRITE_FILE)
  233. {
  234. onFileCallback->OnFile(&threadInfo->onFileStruct);
  235. }
  236. else
  237. {
  238. rakFree_Ex(threadInfo->onFileStruct.fileData, _FILE_AND_LINE_ );
  239. threadInfo->onFileStruct.fileData=threadInfo->postPatchFile;
  240. threadInfo->onFileStruct.byteLengthOfThisFile=threadInfo->postPatchLength;
  241. onFileCallback->OnFile(&threadInfo->onFileStruct);
  242. threadInfo->onFileStruct.fileData=0;
  243. }
  244. }
  245. break;
  246. case PC_ERROR_PATCH_TARGET_MISSING:
  247. {
  248. onFileCallback->OnFile(&threadInfo->onFileStruct);
  249. client->Redownload(threadInfo->onFileStruct.fileName);
  250. }
  251. break;
  252. case PC_ERROR_PATCH_APPLICATION_FAILURE:
  253. {
  254. // Failure - signal class and download this file.
  255. onFileCallback->OnFile(&threadInfo->onFileStruct);
  256. client->Redownload(threadInfo->onFileStruct.fileName);
  257. }
  258. break;
  259. case PC_ERROR_PATCH_RESULT_CHECKSUM_FAILURE:
  260. {
  261. // Failure - signal class and download this file.
  262. onFileCallback->OnFile(&threadInfo->onFileStruct);
  263. client->Redownload(threadInfo->onFileStruct.fileName);
  264. }
  265. break;
  266. default:
  267. {
  268. if (threadInfo->onFileStruct.context.op==PC_WRITE_FILE)
  269. {
  270. onFileCallback->OnFile(&threadInfo->onFileStruct);
  271. }
  272. else
  273. {
  274. rakFree_Ex(threadInfo->onFileStruct.fileData, _FILE_AND_LINE_ );
  275. threadInfo->onFileStruct.fileData=threadInfo->postPatchFile;
  276. onFileCallback->OnFile(&threadInfo->onFileStruct);
  277. threadInfo->onFileStruct.fileData=0;
  278. }
  279. }
  280. break;
  281. }
  282. // if (threadInfo->prePatchFile)
  283. // rakFree_Ex(threadInfo->prePatchFile, _FILE_AND_LINE_ );
  284. if (threadInfo->postPatchFile)
  285. rakFree_Ex(threadInfo->postPatchFile, _FILE_AND_LINE_ );
  286. if (threadInfo->onFileStruct.fileData)
  287. rakFree_Ex(threadInfo->onFileStruct.fileData, _FILE_AND_LINE_ );
  288. RakNet::OP_DELETE(threadInfo, _FILE_AND_LINE_);
  289. }
  290. // If both input and output are empty, we are done.
  291. if (onFileCallback->Update()==false)
  292. canDeleteUser=true;
  293. if ( downloadComplete &&
  294. canDeleteUser &&
  295. threadPool.IsWorking()==false)
  296. {
  297. // Stop threads before calling OnThreadCompletion, in case the other thread starts a new instance of this thread.
  298. StopThreads();
  299. client->OnThreadCompletion();
  300. return false;
  301. }
  302. return true;
  303. }
  304. virtual bool OnDownloadComplete(DownloadCompleteStruct *dcs)
  305. {
  306. downloadComplete=true;
  307. if (onFileCallback->OnDownloadComplete(dcs)==false)
  308. {
  309. canDeleteUser=true;
  310. }
  311. return true;
  312. };
  313. virtual void OnDereference(void)
  314. {
  315. onFileCallback->OnDereference();
  316. StopThreads();
  317. }
  318. virtual bool OnFile(OnFileStruct *onFileStruct)
  319. {
  320. AutopatcherClientThreadInfo *inStruct = RakNet::OP_NEW<AutopatcherClientThreadInfo>( _FILE_AND_LINE_ );
  321. memset(inStruct,0,sizeof(AutopatcherClientThreadInfo));
  322. // inStruct->prePatchFile=0;
  323. inStruct->postPatchFile=0;
  324. inStruct->cbInterface=onFileCallback;
  325. memcpy(&(inStruct->onFileStruct), onFileStruct, sizeof(OnFileStruct));
  326. strcpy(inStruct->applicationDirectory,applicationDirectory);
  327. if (onFileStruct->context.op==PC_HASH_1_WITH_PATCH || onFileStruct->context.op==PC_HASH_2_WITH_PATCH)
  328. onFileStruct->context.op=PC_NOTICE_FILE_DOWNLOADED_PATCH;
  329. else
  330. onFileStruct->context.op=PC_NOTICE_FILE_DOWNLOADED;
  331. onFileCallback->OnFile(onFileStruct);
  332. threadPool.AddInput(AutopatcherClientWorkerThread, inStruct);
  333. // Return false means don't delete OnFileStruct::data
  334. return false;
  335. }
  336. virtual void OnFileProgress(FileProgressStruct *fps)
  337. {
  338. char fullPathToDir[1024];
  339. if (fps->onFileStruct->fileName)
  340. {
  341. strcpy(fullPathToDir, applicationDirectory);
  342. strcat(fullPathToDir, fps->onFileStruct->fileName);
  343. onFileCallback->OnFileProgress(fps);
  344. }
  345. }
  346. };
  347. }
  348. AutopatcherClient::AutopatcherClient()
  349. {
  350. serverId=UNASSIGNED_SYSTEM_ADDRESS;
  351. serverIdIndex=-1;
  352. applicationDirectory[0]=0;
  353. fileListTransfer=0;
  354. priority=HIGH_PRIORITY;
  355. orderingChannel=0;
  356. serverDate=0;
  357. userCB=0;
  358. processThreadCompletion=false;
  359. }
  360. AutopatcherClient::~AutopatcherClient()
  361. {
  362. Clear();
  363. }
  364. void AutopatcherClient::Clear(void)
  365. {
  366. if (fileListTransfer)
  367. fileListTransfer->RemoveReceiver(serverId);
  368. serverId=UNASSIGNED_SYSTEM_ADDRESS;
  369. setId=(unsigned short)-1;
  370. redownloadList.Clear();
  371. copyAndRestartList.Clear();
  372. }
  373. void AutopatcherClient::SetUploadSendParameters(PacketPriority _priority, char _orderingChannel)
  374. {
  375. priority=_priority;
  376. orderingChannel=_orderingChannel;
  377. }
  378. void AutopatcherClient::SetFileListTransferPlugin(FileListTransfer *flt)
  379. {
  380. fileListTransfer=flt;
  381. }
  382. double AutopatcherClient::GetServerDate(void) const
  383. {
  384. return serverDate;
  385. }
  386. void AutopatcherClient::CancelDownload(void)
  387. {
  388. fileListTransfer->CancelReceive(setId);
  389. Clear();
  390. }
  391. void AutopatcherClient::OnThreadCompletion(void)
  392. {
  393. processThreadCompletionMutex.Lock();
  394. processThreadCompletion=true;
  395. processThreadCompletionMutex.Unlock();
  396. }
  397. bool AutopatcherClient::IsPatching(void) const
  398. {
  399. return fileListTransfer->IsHandlerActive(setId);
  400. }
  401. bool AutopatcherClient::PatchApplication(const char *_applicationName, const char *_applicationDirectory, double lastUpdateDate, SystemAddress host, AutopatcherClientCBInterface *onFileCallback, const char *restartOutputFilename, const char *pathToRestartExe)
  402. {
  403. RakAssert(applicationName);
  404. RakAssert(applicationDirectory);
  405. RakAssert(pathToRestartExe);
  406. RakAssert(restartOutputFilename);
  407. // if (rakPeerInterface->GetIndexFromSystemAddress(host)==-1)
  408. // return false;
  409. if (IsPatching())
  410. return false; // Already in the middle of patching.
  411. strcpy(applicationDirectory, _applicationDirectory);
  412. FileList::FixEndingSlash(applicationDirectory);
  413. strcpy(applicationName, _applicationName);
  414. serverId=host;
  415. patchComplete=false;
  416. userCB=onFileCallback;
  417. strcpy(copyOnRestartOut, restartOutputFilename);
  418. strcpy(restartExe, pathToRestartExe);
  419. processThreadCompletionMutex.Lock();
  420. processThreadCompletion=false;
  421. processThreadCompletionMutex.Unlock();
  422. RakNet::BitStream outBitStream;
  423. outBitStream.Write((unsigned char)ID_AUTOPATCHER_GET_CHANGELIST_SINCE_DATE);
  424. StringCompressor::Instance()->EncodeString(applicationName, 512, &outBitStream);
  425. outBitStream.Write(lastUpdateDate);
  426. SendUnified(&outBitStream, priority, RELIABLE_ORDERED, orderingChannel, host, false);
  427. return true;
  428. }
  429. #ifdef _MSC_VER
  430. #pragma warning( disable : 4100 ) // warning C4100: <variable name> : unreferenced formal parameter
  431. #endif
  432. void AutopatcherClient::Update(void)
  433. {
  434. processThreadCompletionMutex.Lock();
  435. if (processThreadCompletion)
  436. {
  437. processThreadCompletion=false;
  438. processThreadCompletionMutex.Unlock();
  439. fileListTransfer->RemoveReceiver(serverId);
  440. // If redownload list, process it
  441. if (redownloadList.fileList.Size())
  442. {
  443. RakNet::BitStream outBitStream;
  444. AutopatcherClientCallback *transferCallback;
  445. transferCallback = RakNet::OP_NEW<AutopatcherClientCallback>( _FILE_AND_LINE_ );
  446. strcpy(transferCallback->applicationDirectory, applicationDirectory);
  447. transferCallback->onFileCallback=userCB;
  448. transferCallback->client=this;
  449. setId = fileListTransfer->SetupReceive(transferCallback, true, serverId);
  450. // Ask for patches for the files in the list that are different from what we have.
  451. outBitStream.Write((unsigned char)ID_AUTOPATCHER_GET_PATCH);
  452. outBitStream.Write(setId);
  453. double lastUpdateData=0;
  454. outBitStream.Write(lastUpdateData);
  455. StringCompressor::Instance()->EncodeString(applicationName, 512, &outBitStream);
  456. redownloadList.Serialize(&outBitStream);
  457. SendUnified(&outBitStream, priority, RELIABLE_ORDERED, orderingChannel, serverId, false);
  458. redownloadList.Clear();
  459. }
  460. else if (copyAndRestartList.fileList.Size())
  461. {
  462. Packet *p = AllocatePacketUnified(1);
  463. p->bitSize=p->length*8;
  464. p->data[0]=ID_AUTOPATCHER_RESTART_APPLICATION;
  465. p->systemAddress=serverId;
  466. p->systemAddress.systemIndex=serverIdIndex;
  467. PushBackPacketUnified(p,false);
  468. FILE *fp;
  469. fp = fopen(copyOnRestartOut, "wt");
  470. RakAssert(fp);
  471. if (fp)
  472. {
  473. fprintf(fp, "#Sleep 1000\n");
  474. unsigned i;
  475. for (i=0; i < copyAndRestartList.fileList.Size(); i++)
  476. {
  477. #ifdef _WIN32
  478. fprintf(fp, "del /q \"%s%s\"\n", applicationDirectory, copyAndRestartList.fileList[i].filename.C_String());
  479. RakString sourceFn = copyAndRestartList.fileList[i].filename;
  480. RakString bareFilename = sourceFn;
  481. bareFilename.StartAfterLastCharacter('/');
  482. fprintf(fp, "rename \"%s%s%s\" \"%s\"\n", applicationDirectory, bareFilename.C_String(), COPY_ON_RESTART_EXTENSION, copyAndRestartList.fileList[i].filename.C_String());
  483. #else
  484. fprintf(fp, "rm -f \"%s%s\"\n", applicationDirectory, copyAndRestartList.fileList[i].filename.C_String());
  485. fprintf(fp, "mv \"%s%s%s\" \"%s\"\n", applicationDirectory, copyAndRestartList.fileList[i].filename.C_String(), COPY_ON_RESTART_EXTENSION, copyAndRestartList.fileList[i].filename.C_String());
  486. #endif
  487. }
  488. #ifdef _WIN32
  489. fprintf(fp, "#CreateProcess \"%s\"\n", restartExe);
  490. #else
  491. fprintf(fp, "chmod +x \"%s\"\n", restartExe);
  492. fprintf(fp, "#CreateProcess \"%s\" &\n", restartExe);
  493. #endif
  494. fprintf(fp, "#DeleteThisFile\n");
  495. fclose(fp);
  496. }
  497. }
  498. else
  499. {
  500. Packet *p = AllocatePacketUnified(1);
  501. p->bitSize=p->length*8;
  502. p->data[0]=ID_AUTOPATCHER_FINISHED;
  503. p->systemAddress=serverId;
  504. p->systemAddress.systemIndex=serverIdIndex;
  505. PushBackPacketUnified(p,false);
  506. }
  507. }
  508. else
  509. {
  510. processThreadCompletionMutex.Unlock();
  511. }
  512. }
  513. void AutopatcherClient::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
  514. {
  515. if (systemAddress==serverId)
  516. Clear();
  517. }
  518. PluginReceiveResult AutopatcherClient::OnReceive(Packet *packet)
  519. {
  520. switch (packet->data[0])
  521. {
  522. case ID_AUTOPATCHER_CREATION_LIST:
  523. return OnCreationList(packet);
  524. case ID_AUTOPATCHER_DELETION_LIST:
  525. OnDeletionList(packet);
  526. return RR_STOP_PROCESSING_AND_DEALLOCATE;
  527. case ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR:
  528. case ID_AUTOPATCHER_CANNOT_DOWNLOAD_ORIGINAL_UNMODIFIED_FILES:
  529. fileListTransfer->RemoveReceiver(serverId);
  530. Clear();
  531. return RR_CONTINUE_PROCESSING;
  532. case ID_AUTOPATCHER_FINISHED_INTERNAL:
  533. return OnDownloadFinishedInternal(packet);
  534. case ID_AUTOPATCHER_FINISHED:
  535. return OnDownloadFinished(packet);
  536. }
  537. return RR_CONTINUE_PROCESSING;
  538. }
  539. #ifdef _MSC_VER
  540. #pragma warning( disable : 4100 ) // warning C4100: <variable name> : unreferenced formal parameter
  541. #endif
  542. void AutopatcherClient::OnShutdown(void)
  543. {
  544. // TODO
  545. }
  546. PluginReceiveResult AutopatcherClient::OnCreationList(Packet *packet)
  547. {
  548. RakAssert(fileListTransfer);
  549. if (packet->systemAddress!=serverId)
  550. return RR_STOP_PROCESSING_AND_DEALLOCATE;
  551. RakNet::BitStream inBitStream(packet->data, packet->length, false);
  552. RakNet::BitStream outBitStream;
  553. FileList remoteFileList, missingOrChanged;
  554. inBitStream.IgnoreBits(8);
  555. if (remoteFileList.Deserialize(&inBitStream)==false)
  556. return RR_STOP_PROCESSING_AND_DEALLOCATE;
  557. inBitStream.Read(serverDate);
  558. double patchApplicationLastUpdateDate;
  559. inBitStream.Read(patchApplicationLastUpdateDate);
  560. // Go through the list of hashes. For each file we already have, remove it from the list.
  561. remoteFileList.ListMissingOrChangedFiles(applicationDirectory, &missingOrChanged, true, false);
  562. if (missingOrChanged.fileList.Size()==0)
  563. {
  564. packet->data[0]=ID_AUTOPATCHER_FINISHED;
  565. return RR_CONTINUE_PROCESSING; // Pass to user
  566. }
  567. // Prepare the transfer plugin to get a file list.
  568. AutopatcherClientCallback *transferCallback;
  569. transferCallback = RakNet::OP_NEW<AutopatcherClientCallback>( _FILE_AND_LINE_ );
  570. strcpy(transferCallback->applicationDirectory, applicationDirectory);
  571. transferCallback->onFileCallback=userCB;
  572. transferCallback->client=this;
  573. setId = fileListTransfer->SetupReceive(transferCallback, true, packet->systemAddress);
  574. // Ask for patches for the files in the list that are different from what we have.
  575. outBitStream.Write((unsigned char)ID_AUTOPATCHER_GET_PATCH);
  576. outBitStream.Write(setId);
  577. outBitStream.Write(patchApplicationLastUpdateDate);
  578. StringCompressor::Instance()->EncodeString(applicationName, 512, &outBitStream);
  579. missingOrChanged.Serialize(&outBitStream);
  580. SendUnified(&outBitStream, priority, RELIABLE_ORDERED, orderingChannel, packet->systemAddress, false);
  581. return RR_STOP_PROCESSING_AND_DEALLOCATE; // Absorb this message
  582. }
  583. void AutopatcherClient::OnDeletionList(Packet *packet)
  584. {
  585. if (packet->systemAddress!=serverId)
  586. return;
  587. RakNet::BitStream inBitStream(packet->data, packet->length, false);
  588. RakNet::BitStream outBitStream;
  589. inBitStream.IgnoreBits(8);
  590. FileList fileList;
  591. if (fileList.Deserialize(&inBitStream)==false)
  592. return;
  593. fileList.DeleteFiles(applicationDirectory);
  594. }
  595. PluginReceiveResult AutopatcherClient::OnDownloadFinished(Packet *packet)
  596. {
  597. RakNet::BitStream inBitStream(packet->data, packet->length, false);
  598. inBitStream.IgnoreBits(8);
  599. // This may have been created internally, with no serverDate written (line 469 or so)
  600. if (inBitStream.GetNumberOfUnreadBits()>7)
  601. {
  602. inBitStream.Read(serverDate);
  603. }
  604. serverId=packet->systemAddress;
  605. serverIdIndex=packet->systemAddress.systemIndex;
  606. return RR_CONTINUE_PROCESSING;
  607. }
  608. PluginReceiveResult AutopatcherClient::OnDownloadFinishedInternal(Packet *packet)
  609. {
  610. RakNet::BitStream inBitStream(packet->data, packet->length, false);
  611. inBitStream.IgnoreBits(8);
  612. serverId=packet->systemAddress;
  613. serverIdIndex=packet->systemAddress.systemIndex;
  614. inBitStream.Read(serverDate);
  615. return RR_STOP_PROCESSING_AND_DEALLOCATE;
  616. }
  617. void AutopatcherClient::CopyAndRestart(const char *filePath)
  618. {
  619. // We weren't able to write applicationDirectory + filePath so we wrote applicationDirectory + filePath + COPY_ON_RESTART_EXTENSION instead
  620. copyAndRestartList.AddFile(filePath,filePath, 0, 0, 0, FileListNodeContext(0,0,0,0));
  621. }
  622. void AutopatcherClient::Redownload(const char *filePath)
  623. {
  624. redownloadList.AddFile(filePath,filePath, 0, 0, 0, FileListNodeContext(0,0,0,0));
  625. }
  626. #ifdef _MSC_VER
  627. #pragma warning( pop )
  628. #endif
粤ICP备19079148号