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