SLikeNet 0.1.3

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FileListTransfer.cpp
Go to the documentation of this file.
1 /*
2 * Original work: 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 * RakNet License.txt file in the licenses directory of this source tree. An additional grant
7 * of patent rights can be found in the RakNet Patents.txt file in the same directory.
8 *
9 *
10 * Modified work: Copyright (c) 2016-2018, SLikeSoft UG (haftungsbeschränkt)
11 *
12 * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
13 * license found in the license.txt file in the root directory of this source tree.
14 */
15
16 #include "slikenet/NativeFeatureIncludes.h"
17 #if _RAKNET_SUPPORT_FileListTransfer==1 && _RAKNET_SUPPORT_FileOperations==1
18
19 #include "slikenet/FileListTransfer.h"
20 #include "slikenet/DS_HuffmanEncodingTree.h"
21 #include "slikenet/FileListTransferCBInterface.h"
22 #include "slikenet/StringCompressor.h"
23 #include "slikenet/FileList.h"
24 #include "slikenet/DS_Queue.h"
25 #include "slikenet/MessageIdentifiers.h"
26 #include "slikenet/types.h"
27 #include "slikenet/peerinterface.h"
28 #include "slikenet/statistics.h"
29 #include "slikenet/IncrementalReadInterface.h"
30 #include "slikenet/assert.h"
31 #include "slikenet/alloca.h"
32
33 namespace SLNet
34 {
35
36 struct FLR_MemoryBlock
37 {
38 char *flrMemoryBlock;
39 };
40
41 struct FileListReceiver
42 {
43 FileListReceiver();
44 ~FileListReceiver();
45 FileListTransferCBInterface *downloadHandler;
46 SystemAddress allowedSender;
47 unsigned short setID;
48 unsigned setCount;
49 unsigned setTotalCompressedTransmissionLength;
50 unsigned setTotalFinalLength;
51 unsigned setTotalDownloadedLength;
52 bool gotSetHeader;
53 bool deleteDownloadHandler;
54 bool isCompressed;
55 int filesReceived;
56 DataStructures::Map<unsigned int, FLR_MemoryBlock> pushedFiles;
57
58 // Notifications
59 unsigned int partLength;
60
61 };
62
63 } // namespace SLNet
64
65 using namespace SLNet;
66
67 FileListReceiver::FileListReceiver() {filesReceived=0; setTotalDownloadedLength=0; partLength=1; DataStructures::Map<unsigned int, FLR_MemoryBlock>::IMPLEMENT_DEFAULT_COMPARISON();}
68 FileListReceiver::~FileListReceiver() {
69 unsigned int i=0;
70 for (i=0; i < pushedFiles.Size(); i++)
71 rakFree_Ex(pushedFiles[i].flrMemoryBlock, _FILE_AND_LINE_ );
72 }
73
74 STATIC_FACTORY_DEFINITIONS(FileListTransfer,FileListTransfer)
75
76 void FileListTransfer::FileToPushRecipient::DeleteThis(void)
77 {
79 for (unsigned int j=0; j < filesToPush.Size(); j++)
80 SLNet::OP_DELETE(filesToPush[j],_FILE_AND_LINE_);
82 SLNet::OP_DELETE(this,_FILE_AND_LINE_);
83 }
84 void FileListTransfer::FileToPushRecipient::AddRef(void)
85 {
86 refCountMutex.Lock();
87 ++refCount;
88 refCountMutex.Unlock();
89 }
90 void FileListTransfer::FileToPushRecipient::Deref(void)
91 {
92 refCountMutex.Lock();
93 --refCount;
94 if (refCount==0)
95 {
96 refCountMutex.Unlock();
97 DeleteThis();
98 return;
99 }
100 refCountMutex.Unlock();
101 }
102 FileListTransfer::FileListTransfer()
103 {
104 setId=0;
105 DataStructures::Map<unsigned short, FileListReceiver*>::IMPLEMENT_DEFAULT_COMPARISON();
106 }
107 FileListTransfer::~FileListTransfer()
108 {
109 threadPool.StopThreads();
110 Clear();
111 }
112 void FileListTransfer::StartIncrementalReadThreads(int numThreads, int threadPriority)
113 {
114 (void) threadPriority;
115
116 threadPool.StartThreads(numThreads, 0);
117 }
118 unsigned short FileListTransfer::SetupReceive(FileListTransferCBInterface *handler, bool deleteHandler, SystemAddress allowedSender)
119 {
120 if (rakPeerInterface && rakPeerInterface->GetConnectionState(allowedSender)!=IS_CONNECTED)
121 return (unsigned short)-1;
122 FileListReceiver *receiver;
123
124 if (fileListReceivers.Has(setId))
125 {
126 receiver=fileListReceivers.Get(setId);
127 receiver->downloadHandler->OnDereference();
128 if (receiver->deleteDownloadHandler)
129 SLNet::OP_DELETE(receiver->downloadHandler, _FILE_AND_LINE_);
130 SLNet::OP_DELETE(receiver, _FILE_AND_LINE_);
131 fileListReceivers.Delete(setId);
132 }
133
134 unsigned short oldId;
135 receiver = SLNet::OP_NEW<FileListReceiver>( _FILE_AND_LINE_ );
136 RakAssert(handler);
137 receiver->downloadHandler=handler;
138 receiver->allowedSender=allowedSender;
139 receiver->gotSetHeader=false;
140 receiver->deleteDownloadHandler=deleteHandler;
141 receiver->setID=setId;
142 fileListReceivers.Set(setId, receiver);
143 oldId=setId;
144 if (++setId==(unsigned short)-1)
145 setId=0;
146 return oldId;
147 }
148
149 void FileListTransfer::Send(FileList *fileList, SLNet::RakPeerInterface *rakPeer, SystemAddress recipient, unsigned short setID, PacketPriority priority, char orderingChannel, IncrementalReadInterface *_incrementalReadInterface, unsigned int _chunkSize)
150 {
151 for (unsigned int flpcIndex=0; flpcIndex < fileListProgressCallbacks.Size(); flpcIndex++)
152 fileList->AddCallback(fileListProgressCallbacks[flpcIndex]);
153
154 unsigned int i, totalLength;
155 SLNet::BitStream outBitstream;
156 bool sendReference;
157 const char *dataBlocks[2];
158 int lengths[2];
159 totalLength=0;
160 for (i=0; i < fileList->fileList.Size(); i++)
161 {
162 const FileListNode &fileListNode = fileList->fileList[i];
163 totalLength+=fileListNode.dataLengthBytes;
164 }
165
166 // Write the chunk header, which contains the frequency table, the total number of files, and the total number of bytes
167 bool anythingToWrite;
168 outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_HEADER);
169 outBitstream.Write(setID);
170 anythingToWrite=fileList->fileList.Size()>0;
171 outBitstream.Write(anythingToWrite);
172 if (anythingToWrite)
173 {
174 outBitstream.WriteCompressed(fileList->fileList.Size());
175 outBitstream.WriteCompressed(totalLength);
176
177 if (rakPeer)
178 rakPeer->Send(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
179 else
180 SendUnified(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
181
182 DataStructures::Queue<FileToPush*> filesToPush;
183
184 for (i=0; i < fileList->fileList.Size(); i++)
185 {
186 sendReference = fileList->fileList[i].isAReference && _incrementalReadInterface!=0;
187 if (sendReference)
188 {
189 FileToPush *fileToPush = SLNet::OP_NEW<FileToPush>(_FILE_AND_LINE_);
190 fileToPush->fileListNode.context=fileList->fileList[i].context;
191 fileToPush->setIndex=i;
192 fileToPush->fileListNode.filename=fileList->fileList[i].filename;
193 fileToPush->fileListNode.fullPathToFile=fileList->fileList[i].fullPathToFile;
194 fileToPush->fileListNode.fileLengthBytes=fileList->fileList[i].fileLengthBytes;
195 fileToPush->fileListNode.dataLengthBytes=fileList->fileList[i].dataLengthBytes;
196 // fileToPush->systemAddress=recipient;
197 //fileToPush->setID=setID;
198 fileToPush->packetPriority=priority;
199 fileToPush->orderingChannel=orderingChannel;
200 fileToPush->currentOffset=0;
201 fileToPush->incrementalReadInterface=_incrementalReadInterface;
202 fileToPush->chunkSize=_chunkSize;
203 filesToPush.Push(fileToPush,_FILE_AND_LINE_);
204 }
205 else
206 {
207 outBitstream.Reset();
208 outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_FILE);
209 outBitstream << fileList->fileList[i].context;
210 // outBitstream.Write(fileList->fileList[i].context);
211 outBitstream.Write(setID);
212 StringCompressor::Instance()->EncodeString(fileList->fileList[i].filename, 512, &outBitstream);
213
214 outBitstream.WriteCompressed(i);
215 outBitstream.WriteCompressed(fileList->fileList[i].dataLengthBytes); // Original length in bytes
216
217 outBitstream.AlignWriteToByteBoundary();
218
219 dataBlocks[0]=(char*) outBitstream.GetData();
220 lengths[0]=outBitstream.GetNumberOfBytesUsed();
221 dataBlocks[1]=fileList->fileList[i].data;
222 lengths[1]=fileList->fileList[i].dataLengthBytes;
223 SendListUnified(dataBlocks,lengths,2,priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
224 }
225 }
226
227 if (filesToPush.IsEmpty()==false)
228 {
229 FileToPushRecipient *ftpr;
230
231 fileToPushRecipientListMutex.Lock();
232 for (i=0; i < fileToPushRecipientList.Size(); i++)
233 {
234 if (fileToPushRecipientList[i]->systemAddress==recipient && fileToPushRecipientList[i]->setId==setId)
235 {
236 // ftpr=fileToPushRecipientList[i];
237 // ftpr->AddRef();
238 // break;
239 RakAssert("setId already in use for this recipient" && 0);
240 }
241 }
242 fileToPushRecipientListMutex.Unlock();
243
244 //if (ftpr==0)
245 //{
246 ftpr = SLNet::OP_NEW<FileToPushRecipient>(_FILE_AND_LINE_);
247 ftpr->systemAddress=recipient;
248 ftpr->setId=setID;
249 ftpr->refCount=2; // Allocated and in the list
250 fileToPushRecipientList.Push(ftpr, _FILE_AND_LINE_);
251 //}
252 while (filesToPush.IsEmpty()==false)
253 {
255 ftpr->filesToPush.Push(filesToPush.Pop(), _FILE_AND_LINE_);
257 }
258 // ftpr out of scope
259 ftpr->Deref();
260 SendIRIToAddress(recipient, setID);
261 return;
262 }
263 else
264 {
265 for (unsigned int flpcIndex=0; flpcIndex < fileListProgressCallbacks.Size(); flpcIndex++)
266 fileListProgressCallbacks[flpcIndex]->OnFilePushesComplete(recipient, setID);
267 }
268 }
269 else
270 {
271 for (unsigned int flpcIndex=0; flpcIndex < fileListProgressCallbacks.Size(); flpcIndex++)
272 fileListProgressCallbacks[flpcIndex]->OnFilePushesComplete(recipient, setID);
273
274 if (rakPeer)
275 rakPeer->Send(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
276 else
277 SendUnified(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
278 }
279 }
280
281 bool FileListTransfer::DecodeSetHeader(Packet *packet)
282 {
283 bool anythingToWrite=false;
284 unsigned short setID;
285 SLNet::BitStream inBitStream(packet->data, packet->length, false);
286 inBitStream.IgnoreBits(8);
287 inBitStream.Read(setID);
288 FileListReceiver *fileListReceiver;
289 if (fileListReceivers.Has(setID)==false)
290 {
291 // If this assert hits you didn't call SetupReceive
292 #ifdef _DEBUG
293 RakAssert(0);
294 #endif
295 return false;
296 }
297 fileListReceiver=fileListReceivers.Get(setID);
298 if (fileListReceiver->allowedSender!=packet->systemAddress)
299 {
300 #ifdef _DEBUG
301 RakAssert(0);
302 #endif
303 return false;
304 }
305
306 #ifdef _DEBUG
307 RakAssert(fileListReceiver->gotSetHeader==false);
308 #endif
309
310 inBitStream.Read(anythingToWrite);
311
312 if (anythingToWrite)
313 {
314 inBitStream.ReadCompressed(fileListReceiver->setCount);
315 if (inBitStream.ReadCompressed(fileListReceiver->setTotalFinalLength))
316 {
317 fileListReceiver->setTotalCompressedTransmissionLength=fileListReceiver->setTotalFinalLength;
318 fileListReceiver->gotSetHeader=true;
319 return true;
320 }
321
322 }
323 else
324 {
325 FileListTransferCBInterface::DownloadCompleteStruct dcs;
326 dcs.setID=fileListReceiver->setID;
327 dcs.numberOfFilesInThisSet=fileListReceiver->setCount;
328 dcs.byteLengthOfThisSet=fileListReceiver->setTotalFinalLength;
329 dcs.senderSystemAddress=packet->systemAddress;
330 dcs.senderGuid=packet->guid;
331
332 if (fileListReceiver->downloadHandler->OnDownloadComplete(&dcs)==false)
333 {
334 fileListReceiver->downloadHandler->OnDereference();
335 fileListReceivers.Delete(setID);
336 if (fileListReceiver->deleteDownloadHandler)
337 SLNet::OP_DELETE(fileListReceiver->downloadHandler, _FILE_AND_LINE_);
338 SLNet::OP_DELETE(fileListReceiver, _FILE_AND_LINE_);
339 }
340
341 return true;
342 }
343
344 return false;
345 }
346
347 bool FileListTransfer::DecodeFile(Packet *packet, bool isTheFullFile)
348 {
349 FileListTransferCBInterface::OnFileStruct onFileStruct;
350 SLNet::BitStream inBitStream(packet->data, packet->length, false);
351 inBitStream.IgnoreBits(8);
352
353 onFileStruct.senderSystemAddress=packet->systemAddress;
354 onFileStruct.senderGuid=packet->guid;
355
356 unsigned int partCount=0;
357 unsigned int partTotal=0;
358 unsigned int partLength=0;
359 onFileStruct.fileData=0;
360 if (isTheFullFile==false)
361 {
362 // Disable endian swapping on reading this, as it's generated locally in ReliabilityLayer.cpp
363 inBitStream.ReadBits( (unsigned char* ) &partCount, BYTES_TO_BITS(sizeof(partCount)), true );
364 inBitStream.ReadBits( (unsigned char* ) &partTotal, BYTES_TO_BITS(sizeof(partTotal)), true );
365 inBitStream.ReadBits( (unsigned char* ) &partLength, BYTES_TO_BITS(sizeof(partLength)), true );
366 inBitStream.IgnoreBits(8);
367 // The header is appended to every chunk, which we continue to read after this statement flrMemoryBlock
368 }
369 inBitStream >> onFileStruct.context;
370 // inBitStream.Read(onFileStruct.context);
371 inBitStream.Read(onFileStruct.setID);
372 FileListReceiver *fileListReceiver;
373 if (fileListReceivers.Has(onFileStruct.setID)==false)
374 {
375 return false;
376 }
377 fileListReceiver=fileListReceivers.Get(onFileStruct.setID);
378 if (fileListReceiver->allowedSender!=packet->systemAddress)
379 {
380 #ifdef _DEBUG
381 RakAssert(0);
382 #endif
383 return false;
384 }
385
386 #ifdef _DEBUG
387 RakAssert(fileListReceiver->gotSetHeader==true);
388 #endif
389
390 if (StringCompressor::Instance()->DecodeString(onFileStruct.fileName, 512, &inBitStream)==false)
391 {
392 #ifdef _DEBUG
393 RakAssert(0);
394 #endif
395 return false;
396 }
397
398 inBitStream.ReadCompressed(onFileStruct.fileIndex);
399 inBitStream.ReadCompressed(onFileStruct.byteLengthOfThisFile);
400
401 onFileStruct.numberOfFilesInThisSet=fileListReceiver->setCount;
402 onFileStruct.byteLengthOfThisSet=fileListReceiver->setTotalFinalLength;
403
404 if (isTheFullFile)
405 {
406 onFileStruct.bytesDownloadedForThisFile=onFileStruct.byteLengthOfThisFile;
407 fileListReceiver->setTotalDownloadedLength+=onFileStruct.byteLengthOfThisFile;
408 onFileStruct.bytesDownloadedForThisSet=fileListReceiver->setTotalDownloadedLength;
409 }
410 else
411 {
412 onFileStruct.bytesDownloadedForThisFile=partLength*partCount;
413 onFileStruct.bytesDownloadedForThisSet=fileListReceiver->setTotalDownloadedLength+onFileStruct.bytesDownloadedForThisFile;
414 }
415
416 // User callback for this file.
417 if (isTheFullFile)
418 {
419 inBitStream.AlignReadToByteBoundary();
420 onFileStruct.fileData = (char*) rakMalloc_Ex( (size_t) onFileStruct.byteLengthOfThisFile, _FILE_AND_LINE_ );
421 inBitStream.Read((char*)onFileStruct.fileData, onFileStruct.byteLengthOfThisFile);
422
423 FileListTransferCBInterface::FileProgressStruct fps;
424 fps.onFileStruct=&onFileStruct;
425 fps.partCount=1;
426 fps.partTotal=1;
427 fps.dataChunkLength=onFileStruct.byteLengthOfThisFile;
428 fps.firstDataChunk=onFileStruct.fileData;
429 fps.iriDataChunk=onFileStruct.fileData;
430 fps.allocateIrIDataChunkAutomatically=true;
431 fps.iriWriteOffset=0;
432 fps.senderSystemAddress=packet->systemAddress;
433 fps.senderGuid=packet->guid;
434 fileListReceiver->downloadHandler->OnFileProgress(&fps);
435
436 // Got a complete file
437 // Either we are using IncrementalReadInterface and it was a small file or
438 // We are not using IncrementalReadInterface
439 if (fileListReceiver->downloadHandler->OnFile(&onFileStruct))
440 rakFree_Ex(onFileStruct.fileData, _FILE_AND_LINE_ );
441
442 fileListReceiver->filesReceived++;
443
444 // If this set is done, free the memory for it.
445 if ((int) fileListReceiver->setCount==fileListReceiver->filesReceived)
446 {
447 FileListTransferCBInterface::DownloadCompleteStruct dcs;
448 dcs.setID=fileListReceiver->setID;
449 dcs.numberOfFilesInThisSet=fileListReceiver->setCount;
450 dcs.byteLengthOfThisSet=fileListReceiver->setTotalFinalLength;
451 dcs.senderSystemAddress=packet->systemAddress;
452 dcs.senderGuid=packet->guid;
453
454 if (fileListReceiver->downloadHandler->OnDownloadComplete(&dcs)==false)
455 {
456 fileListReceiver->downloadHandler->OnDereference();
457 if (fileListReceiver->deleteDownloadHandler)
458 SLNet::OP_DELETE(fileListReceiver->downloadHandler, _FILE_AND_LINE_);
459 fileListReceivers.Delete(onFileStruct.setID);
460 SLNet::OP_DELETE(fileListReceiver, _FILE_AND_LINE_);
461 }
462 }
463
464 }
465 else
466 {
467 inBitStream.AlignReadToByteBoundary();
468
469 char *firstDataChunk;
470 unsigned int unreadBits = inBitStream.GetNumberOfUnreadBits();
471 unsigned int unreadBytes = BITS_TO_BYTES(unreadBits);
472 firstDataChunk=(char*) inBitStream.GetData()+BITS_TO_BYTES(inBitStream.GetReadOffset());
473
474 FileListTransferCBInterface::FileProgressStruct fps;
475 fps.onFileStruct=&onFileStruct;
476 fps.partCount=partCount;
477 fps.partTotal=partTotal;
478 fps.dataChunkLength=unreadBytes;
479 fps.firstDataChunk=firstDataChunk;
480 fps.iriDataChunk=0;
481 fps.allocateIrIDataChunkAutomatically=true;
482 fps.iriWriteOffset=0;
483 fps.senderSystemAddress=packet->systemAddress;
484 fps.senderGuid=packet->guid;
485
486 // Remote system is sending a complete file, but the file is large enough that we get ID_PROGRESS_NOTIFICATION from the transport layer
487 fileListReceiver->downloadHandler->OnFileProgress(&fps);
488
489 }
490
491 return true;
492 }
493 PluginReceiveResult FileListTransfer::OnReceive(Packet *packet)
494 {
495 switch (packet->data[0])
496 {
497 case ID_FILE_LIST_TRANSFER_HEADER:
498 DecodeSetHeader(packet);
499 return RR_STOP_PROCESSING_AND_DEALLOCATE;
500 case ID_FILE_LIST_TRANSFER_FILE:
501 DecodeFile(packet, true);
502 return RR_STOP_PROCESSING_AND_DEALLOCATE;
503 case ID_FILE_LIST_REFERENCE_PUSH:
504 OnReferencePush(packet, true);
505 return RR_STOP_PROCESSING_AND_DEALLOCATE;
506 case ID_FILE_LIST_REFERENCE_PUSH_ACK:
507 OnReferencePushAck(packet);
508 return RR_STOP_PROCESSING_AND_DEALLOCATE;
509 case ID_DOWNLOAD_PROGRESS:
510 if (packet->length>sizeof(MessageID)+sizeof(unsigned int)*3)
511 {
512 if (packet->data[sizeof(MessageID)+sizeof(unsigned int)*3]==ID_FILE_LIST_TRANSFER_FILE)
513 {
514 DecodeFile(packet, false);
515 return RR_STOP_PROCESSING_AND_DEALLOCATE;
516 }
517 if (packet->data[sizeof(MessageID)+sizeof(unsigned int)*3]==ID_FILE_LIST_REFERENCE_PUSH)
518 {
519 OnReferencePush(packet, false);
520 return RR_STOP_PROCESSING_AND_DEALLOCATE;
521 }
522 }
523 break;
524 }
525
526 return RR_CONTINUE_PROCESSING;
527 }
528 void FileListTransfer::OnRakPeerShutdown(void)
529 {
530 threadPool.StopThreads();
531 threadPool.ClearInput();
532 Clear();
533 }
534 void FileListTransfer::Clear(void)
535 {
536 unsigned i;
537 for (i=0; i < fileListReceivers.Size(); i++)
538 {
539 fileListReceivers[i]->downloadHandler->OnDereference();
540 if (fileListReceivers[i]->deleteDownloadHandler)
541 SLNet::OP_DELETE(fileListReceivers[i]->downloadHandler, _FILE_AND_LINE_);
542 SLNet::OP_DELETE(fileListReceivers[i], _FILE_AND_LINE_);
543 }
544 fileListReceivers.Clear();
545
546 fileToPushRecipientListMutex.Lock();
547 for (i=0; i < fileToPushRecipientList.Size(); i++)
548 {
549 FileToPushRecipient *ftpr = fileToPushRecipientList[i];
550 // Taken out of the list
551 ftpr->Deref();
552 }
553 fileToPushRecipientList.Clear(false,_FILE_AND_LINE_);
554 fileToPushRecipientListMutex.Unlock();
555
556 //filesToPush.Clear(false, _FILE_AND_LINE_);
557 }
558 void FileListTransfer::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
559 {
560 (void) lostConnectionReason;
561 (void) rakNetGUID;
562
563 RemoveReceiver(systemAddress);
564 }
565 void FileListTransfer::CancelReceive(unsigned short inSetId)
566 {
567 if (fileListReceivers.Has(inSetId)==false)
568 {
569 #ifdef _DEBUG
570 RakAssert(0);
571 #endif
572 return;
573 }
574 FileListReceiver *fileListReceiver=fileListReceivers.Get(inSetId);
575 fileListReceiver->downloadHandler->OnDereference();
576 if (fileListReceiver->deleteDownloadHandler)
577 SLNet::OP_DELETE(fileListReceiver->downloadHandler, _FILE_AND_LINE_);
578 SLNet::OP_DELETE(fileListReceiver, _FILE_AND_LINE_);
579 fileListReceivers.Delete(inSetId);
580 }
581 void FileListTransfer::RemoveReceiver(SystemAddress systemAddress)
582 {
583 unsigned i;
584 i=0;
585 threadPool.LockInput();
586 while (i < threadPool.InputSize())
587 {
588 if (threadPool.GetInputAtIndex(i).systemAddress==systemAddress)
589 {
590 threadPool.RemoveInputAtIndex(i);
591 }
592 else
593 i++;
594 }
595 threadPool.UnlockInput();
596
597 i=0;
598 while (i < fileListReceivers.Size())
599 {
600 if (fileListReceivers[i]->allowedSender==systemAddress)
601 {
602 fileListReceivers[i]->downloadHandler->OnDereference();
603 if (fileListReceivers[i]->deleteDownloadHandler)
604 SLNet::OP_DELETE(fileListReceivers[i]->downloadHandler, _FILE_AND_LINE_);
605 SLNet::OP_DELETE(fileListReceivers[i], _FILE_AND_LINE_);
606 fileListReceivers.RemoveAtIndex(i);
607 }
608 else
609 i++;
610 }
611
612 fileToPushRecipientListMutex.Lock();
613 i=0;
614 while (i < fileToPushRecipientList.Size())
615 {
616 if (fileToPushRecipientList[i]->systemAddress==systemAddress)
617 {
618 FileToPushRecipient *ftpr = fileToPushRecipientList[i];
619
620 // Tell the user that this recipient was lost
621 for (unsigned int flpcIndex=0; flpcIndex < fileListProgressCallbacks.Size(); flpcIndex++)
622 fileListProgressCallbacks[flpcIndex]->OnSendAborted(ftpr->systemAddress);
623
624 fileToPushRecipientList.RemoveAtIndex(i);
625 // Taken out of the list
626 ftpr->Deref();
627 }
628 else
629 {
630 i++;
631 }
632 }
633 fileToPushRecipientListMutex.Unlock();
634 }
635 bool FileListTransfer::IsHandlerActive(unsigned short inSetId)
636 {
637 return fileListReceivers.Has(inSetId);
638 }
639 void FileListTransfer::AddCallback(FileListProgress *cb)
640 {
641 if (cb==0)
642 return;
643
644 if (fileListProgressCallbacks.GetIndexOf(cb)==(unsigned int) -1)
645 fileListProgressCallbacks.Push(cb, _FILE_AND_LINE_);
646 }
647 void FileListTransfer::RemoveCallback(FileListProgress *cb)
648 {
649 unsigned int idx = fileListProgressCallbacks.GetIndexOf(cb);
650 if (idx!=(unsigned int) -1)
651 fileListProgressCallbacks.RemoveAtIndex(idx);
652 }
653 void FileListTransfer::ClearCallbacks(void)
654 {
655 fileListProgressCallbacks.Clear(true, _FILE_AND_LINE_);
656 }
657 void FileListTransfer::GetCallbacks(DataStructures::List<FileListProgress*> &callbacks)
658 {
659 callbacks = fileListProgressCallbacks;
660 }
661
662 void FileListTransfer::Update(void)
663 {
664 unsigned i;
665 i=0;
666 while (i < fileListReceivers.Size())
667 {
668 if (fileListReceivers[i]->downloadHandler->Update()==false)
669 {
670 fileListReceivers[i]->downloadHandler->OnDereference();
671 if (fileListReceivers[i]->deleteDownloadHandler)
672 SLNet::OP_DELETE(fileListReceivers[i]->downloadHandler, _FILE_AND_LINE_);
673 SLNet::OP_DELETE(fileListReceivers[i], _FILE_AND_LINE_);
674 fileListReceivers.RemoveAtIndex(i);
675 }
676 else
677 i++;
678 }
679 }
680 void FileListTransfer::OnReferencePush(Packet *packet, bool isTheFullFile)
681 {
682 SLNet::BitStream refPushAck;
683 if (isTheFullFile==false)
684 {
685 // 12/23/09 Why do I care about ID_DOWNLOAD_PROGRESS for reference pushes?
686 // 2/16/2012 I care because a reference push is 16 megabytes by default. Also, if it is the last file "if (ftpr->filesToPush.Size()<2)" or total file size exceeds smallFileTotalSize it always sends a reference push.
687 // return;
688 }
689
690 FileListTransferCBInterface::OnFileStruct onFileStruct;
691 SLNet::BitStream inBitStream(packet->data, packet->length, false);
692 inBitStream.IgnoreBits(8);
693
694 unsigned int partCount=0;
695 unsigned int partTotal=1;
696 unsigned int partLength=0;
697 onFileStruct.fileData=0;
698 if (isTheFullFile==false)
699 {
700 // Disable endian swapping on reading this, as it's generated locally in ReliabilityLayer.cpp
701 inBitStream.ReadBits( (unsigned char* ) &partCount, BYTES_TO_BITS(sizeof(partCount)), true );
702 inBitStream.ReadBits( (unsigned char* ) &partTotal, BYTES_TO_BITS(sizeof(partTotal)), true );
703 inBitStream.ReadBits( (unsigned char* ) &partLength, BYTES_TO_BITS(sizeof(partLength)), true );
704 inBitStream.IgnoreBits(8);
705 // The header is appended to every chunk, which we continue to read after this statement flrMemoryBlock
706 }
707
708 inBitStream >> onFileStruct.context;
709 inBitStream.Read(onFileStruct.setID);
710
711 // This is not a progress notification, it is actually the entire packet
712 if (isTheFullFile==true)
713 {
714 refPushAck.Write((MessageID)ID_FILE_LIST_REFERENCE_PUSH_ACK);
715 refPushAck.Write(onFileStruct.setID);
716 SendUnified(&refPushAck,HIGH_PRIORITY, RELIABLE, 0, packet->systemAddress, false);
717 }
718
719 // inBitStream.Read(onFileStruct.context);
720 FileListReceiver *fileListReceiver;
721 if (fileListReceivers.Has(onFileStruct.setID)==false)
722 {
723 return;
724 }
725 fileListReceiver=fileListReceivers.Get(onFileStruct.setID);
726 if (fileListReceiver->allowedSender!=packet->systemAddress)
727 {
728 #ifdef _DEBUG
729 RakAssert(0);
730 #endif
731 return;
732 }
733
734 #ifdef _DEBUG
735 RakAssert(fileListReceiver->gotSetHeader==true);
736 #endif
737
738 if (StringCompressor::Instance()->DecodeString(onFileStruct.fileName, 512, &inBitStream)==false)
739 {
740 #ifdef _DEBUG
741 RakAssert(0);
742 #endif
743 return;
744 }
745
746 inBitStream.ReadCompressed(onFileStruct.fileIndex);
747 inBitStream.ReadCompressed(onFileStruct.byteLengthOfThisFile);
748 unsigned int offset;
749 unsigned int chunkLength;
750 inBitStream.ReadCompressed(offset);
751 inBitStream.ReadCompressed(chunkLength);
752
753 bool lastChunk=false;
754 inBitStream.Read(lastChunk);
755 bool finished = lastChunk && isTheFullFile;
756
757 if (isTheFullFile==false)
758 fileListReceiver->partLength=partLength;
759
760 FLR_MemoryBlock mb;
761 if (fileListReceiver->pushedFiles.Has(onFileStruct.fileIndex)==false)
762 {
763 if (onFileStruct.byteLengthOfThisFile <= SLNET_MAX_RETRIEVABLE_FILESIZE)
764 mb.flrMemoryBlock = (char*)rakMalloc_Ex(onFileStruct.byteLengthOfThisFile, _FILE_AND_LINE_);
765 else
766 mb.flrMemoryBlock = nullptr;
767 fileListReceiver->pushedFiles.SetNew(onFileStruct.fileIndex, mb);
768 }
769 else
770 {
771 mb=fileListReceiver->pushedFiles.Get(onFileStruct.fileIndex);
772 }
773
774 unsigned int unreadBits = inBitStream.GetNumberOfUnreadBits();
775 unsigned int unreadBytes = BITS_TO_BYTES(unreadBits);
776 unsigned int amountToRead;
777 if (isTheFullFile)
778 amountToRead=chunkLength;
779 else
780 amountToRead=unreadBytes;
781
782 inBitStream.AlignReadToByteBoundary();
783
784 FileListTransferCBInterface::FileProgressStruct fps;
785
786 if (isTheFullFile)
787 {
788 if (mb.flrMemoryBlock)
789 {
790 // Either the very first block, or a subsequent block and allocateIrIDataChunkAutomatically was true for the first block
791 memcpy(mb.flrMemoryBlock+offset, inBitStream.GetData()+BITS_TO_BYTES(inBitStream.GetReadOffset()), amountToRead);
792 fps.iriDataChunk=mb.flrMemoryBlock+offset;
793 }
794 else
795 {
796 // In here mb.flrMemoryBlock is null
797 // This means the first block explicitly deallocated the memory, and no blocks will be permanently held by RakNet
798 fps.iriDataChunk=(char*) inBitStream.GetData()+BITS_TO_BYTES(inBitStream.GetReadOffset());
799 }
800
801 onFileStruct.bytesDownloadedForThisFile=offset+chunkLength;
802 fileListReceiver->setTotalDownloadedLength+=chunkLength;
803 onFileStruct.bytesDownloadedForThisSet=fileListReceiver->setTotalDownloadedLength;
804 }
805 else
806 {
807 onFileStruct.bytesDownloadedForThisFile=offset+partLength*partCount;
808 onFileStruct.bytesDownloadedForThisSet=fileListReceiver->setTotalDownloadedLength+partCount*partLength;
809 fps.iriDataChunk=(char*) inBitStream.GetData()+BITS_TO_BYTES(inBitStream.GetReadOffset());
810 }
811
812 onFileStruct.numberOfFilesInThisSet=fileListReceiver->setCount;
813 // onFileStruct.setTotalCompressedTransmissionLength=fileListReceiver->setTotalCompressedTransmissionLength;
814 onFileStruct.byteLengthOfThisSet=fileListReceiver->setTotalFinalLength;
815 // Note: mb.flrMemoryBlock may be null here
816 onFileStruct.fileData=mb.flrMemoryBlock;
817 onFileStruct.senderSystemAddress=packet->systemAddress;
818 onFileStruct.senderGuid=packet->guid;
819
820 unsigned int totalNotifications;
821 unsigned int currentNotificationIndex;
822 if (chunkLength==0 || chunkLength==onFileStruct.byteLengthOfThisFile)
823 totalNotifications=1;
824 else
825 totalNotifications = onFileStruct.byteLengthOfThisFile / chunkLength + 1;
826
827 if (chunkLength==0)
828 currentNotificationIndex = 0;
829 else
830 currentNotificationIndex = offset / chunkLength;
831
832 fps.onFileStruct=&onFileStruct;
833 fps.partCount=currentNotificationIndex;
834 fps.partTotal=totalNotifications;
835 fps.dataChunkLength=amountToRead;
836 fps.firstDataChunk=mb.flrMemoryBlock;
837 fps.allocateIrIDataChunkAutomatically=true;
838 fps.onFileStruct->fileData=mb.flrMemoryBlock;
839 fps.iriWriteOffset=offset;
840 fps.senderSystemAddress=packet->systemAddress;
841 fps.senderGuid=packet->guid;
842
843 if (finished)
844 {
845 char *oldFileData=fps.onFileStruct->fileData;
846 if (fps.partCount==0)
847 fps.firstDataChunk=fps.iriDataChunk;
848 if (fps.partTotal==1)
849 fps.onFileStruct->fileData=fps.iriDataChunk;
850 fileListReceiver->downloadHandler->OnFileProgress(&fps);
851
852 // Incremental read interface sent us a file chunk
853 // This is the last file chunk we were waiting for to consider the file done
854 if (fileListReceiver->downloadHandler->OnFile(&onFileStruct))
855 rakFree_Ex(oldFileData, _FILE_AND_LINE_ );
856 fileListReceiver->pushedFiles.Delete(onFileStruct.fileIndex);
857
858 fileListReceiver->filesReceived++;
859
860 // If this set is done, free the memory for it.
861 if ((int) fileListReceiver->setCount==fileListReceiver->filesReceived)
862 {
863 FileListTransferCBInterface::DownloadCompleteStruct dcs;
864 dcs.setID=fileListReceiver->setID;
865 dcs.numberOfFilesInThisSet=fileListReceiver->setCount;
866 dcs.byteLengthOfThisSet=fileListReceiver->setTotalFinalLength;
867 dcs.senderSystemAddress=packet->systemAddress;
868 dcs.senderGuid=packet->guid;
869
870 if (fileListReceiver->downloadHandler->OnDownloadComplete(&dcs)==false)
871 {
872 fileListReceiver->downloadHandler->OnDereference();
873 fileListReceivers.Delete(onFileStruct.setID);
874 if (fileListReceiver->deleteDownloadHandler)
875 SLNet::OP_DELETE(fileListReceiver->downloadHandler, _FILE_AND_LINE_);
876 SLNet::OP_DELETE(fileListReceiver, _FILE_AND_LINE_);
877 }
878 }
879 }
880 else
881 {
882 if (isTheFullFile)
883 {
884 // 12/23/09 Don't use OnReferencePush anymore, just use OnFileProgress
885 fileListReceiver->downloadHandler->OnFileProgress(&fps);
886
887 if (fps.allocateIrIDataChunkAutomatically==false)
888 {
889 rakFree_Ex(fileListReceiver->pushedFiles.Get(onFileStruct.fileIndex).flrMemoryBlock, _FILE_AND_LINE_ );
890 fileListReceiver->pushedFiles.Get(onFileStruct.fileIndex).flrMemoryBlock=0;
891 }
892 }
893 else
894 {
895 // This is a download progress notification for a file chunk using incremental read interface
896 // We don't have all the data for this chunk yet
897
898 totalNotifications = onFileStruct.byteLengthOfThisFile / fileListReceiver->partLength + 1;
899 if (isTheFullFile==false)
900 currentNotificationIndex = (offset+partCount*fileListReceiver->partLength) / fileListReceiver->partLength ;
901 else
902 currentNotificationIndex = (offset+chunkLength) / fileListReceiver->partLength ;
903 unreadBytes = onFileStruct.byteLengthOfThisFile - ((currentNotificationIndex+1) * fileListReceiver->partLength);
904 fps.partCount=currentNotificationIndex;
905 fps.partTotal=totalNotifications;
906
907 // 2/19/2013 Why was this check here? It prevent smaller progress notifications
908 // if (rakPeerInterface)
909 {
910 // Thus chunk is incomplete
911 fps.iriDataChunk=0;
912
913 fileListReceiver->downloadHandler->OnFileProgress(&fps);
914 }
915 }
916 }
917
918 return;
919 }
920 namespace SLNet
921 {
922
923 /*
924 SendIRIToAddress - executes from Send(). =
925 1, Find the recipient to send for
926 2. Send ID_FILE_LIST_TRANSFER_FILE for each small file in the queue of ifles to be sent
927 3. If the file we are working on is done, remove it from the list
928 4. Send ID_FILE_LIST_REFERENCE_PUSH for the file we are working on
929
930 File sender:
931 ID_FILE_LIST_REFERENCE_PUSH sent from end of SendIRIToAddressCB
932
933 Recipient:
934 send ID_FILE_LIST_REFERENCE_PUSH_ACK sent from OnReferencePush() when 2nd parameter is true.
935
936 File sender:
937 Got ID_FILE_LIST_REFERENCE_PUSH_ACK. Calls OnReferencePushAck, calls SendIRIToAddress, calls SendIRIToAddressCB
938 */
939
940 int SendIRIToAddressCB(FileListTransfer::ThreadData threadData, bool *returnOutput, void* perThreadData)
941 {
942 (void) perThreadData;
943
944 FileListTransfer *fileListTransfer = threadData.fileListTransfer;
945 SystemAddress systemAddress = threadData.systemAddress;
946 unsigned short setId = threadData.setId;
947 *returnOutput=false;
948
949 // Was previously using GetStatistics to get outgoing buffer size, but TCP with UnifiedSend doesn't have this
950 unsigned int bytesRead;
951 const char *dataBlocks[2];
952 int lengths[2];
953 unsigned int smallFileTotalSize=0;
954 SLNet::BitStream outBitstream;
955 unsigned int ftpIndex;
956
957 fileListTransfer->fileToPushRecipientListMutex.Lock();
958 for (ftpIndex=0; ftpIndex < fileListTransfer->fileToPushRecipientList.Size(); ftpIndex++)
959 {
960 FileListTransfer::FileToPushRecipient *ftpr = fileListTransfer->fileToPushRecipientList[ftpIndex];
961 // Referenced by both ftpr and list
962 ftpr->AddRef();
963
964 fileListTransfer->fileToPushRecipientListMutex.Unlock();
965
966 if (ftpr->systemAddress==systemAddress && ftpr->setId==setId)
967 {
968 FileListTransfer::FileToPush *ftp;
970 ftp = ftpr->filesToPush.Pop();
972
973 // Read and send chunk. If done, delete at this index
974 void *buff = rakMalloc_Ex(ftp->chunkSize, _FILE_AND_LINE_);
975 if (buff==0)
976 {
978 ftpr->filesToPush.PushAtHead(ftp,0,_FILE_AND_LINE_);
980
981 ftpr->Deref();
982 notifyOutOfMemory(_FILE_AND_LINE_);
983 return 0;
984 }
985
986 // Read the next file chunk
987 bytesRead=ftp->incrementalReadInterface->GetFilePart(ftp->fileListNode.fullPathToFile, ftp->currentOffset, ftp->chunkSize, buff, ftp->fileListNode.context);
988
989 bool done = ftp->fileListNode.dataLengthBytes == ftp->currentOffset+bytesRead;
990 while (done && ftp->currentOffset==0 && smallFileTotalSize<ftp->chunkSize)
991 {
993 // The reason for 2 is that ID_FILE_LIST_REFERENCE_PUSH gets ID_FILE_LIST_REFERENCE_PUSH_ACK. WIthout ID_FILE_LIST_REFERENCE_PUSH_ACK, SendIRIToAddressCB would not be called again
994 if (ftpr->filesToPush.Size()<2)
995 {
997 break;
998 }
1000
1001 // Send all small files at once, rather than wait for ID_FILE_LIST_REFERENCE_PUSH. But at least one ID_FILE_LIST_REFERENCE_PUSH must be sent
1002 outBitstream.Reset();
1003 outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_FILE);
1004 // outBitstream.Write(ftp->fileListNode.context);
1005 outBitstream << ftp->fileListNode.context;
1006 outBitstream.Write(setId);
1007 StringCompressor::Instance()->EncodeString(ftp->fileListNode.filename, 512, &outBitstream);
1008 outBitstream.WriteCompressed(ftp->setIndex);
1009 outBitstream.WriteCompressed(ftp->fileListNode.dataLengthBytes); // Original length in bytes
1010 outBitstream.AlignWriteToByteBoundary();
1011 dataBlocks[0]=(char*) outBitstream.GetData();
1012 lengths[0]=outBitstream.GetNumberOfBytesUsed();
1013 dataBlocks[1]=(const char*) buff;
1014 lengths[1]=bytesRead;
1015
1016 fileListTransfer->SendListUnified(dataBlocks,lengths,2,ftp->packetPriority, RELIABLE_ORDERED, ftp->orderingChannel, systemAddress, false);
1017
1018 // LWS : fixed freed pointer reference
1019 // unsigned int chunkSize = ftp->chunkSize;
1020 SLNet::OP_DELETE(ftp,_FILE_AND_LINE_);
1021 smallFileTotalSize+=bytesRead;
1022 //done = bytesRead!=ftp->chunkSize;
1024 ftp = ftpr->filesToPush.Pop();
1026
1027 bytesRead=ftp->incrementalReadInterface->GetFilePart(ftp->fileListNode.fullPathToFile, ftp->currentOffset, ftp->chunkSize, buff, ftp->fileListNode.context);
1028 done = ftp->fileListNode.dataLengthBytes == ftp->currentOffset+bytesRead;
1029 }
1030
1031
1032 outBitstream.Reset();
1033 outBitstream.Write((MessageID)ID_FILE_LIST_REFERENCE_PUSH);
1034 // outBitstream.Write(ftp->fileListNode.context);
1035 outBitstream << ftp->fileListNode.context;
1036 outBitstream.Write(setId);
1037 StringCompressor::Instance()->EncodeString(ftp->fileListNode.filename, 512, &outBitstream);
1038 outBitstream.WriteCompressed(ftp->setIndex);
1039 outBitstream.WriteCompressed(ftp->fileListNode.dataLengthBytes); // Original length in bytes
1040 outBitstream.WriteCompressed(ftp->currentOffset);
1041 ftp->currentOffset+=bytesRead;
1042 outBitstream.WriteCompressed(bytesRead);
1043 outBitstream.Write(done);
1044
1045 for (unsigned int flpcIndex=0; flpcIndex < fileListTransfer->fileListProgressCallbacks.Size(); flpcIndex++)
1046 fileListTransfer->fileListProgressCallbacks[flpcIndex]->OnFilePush(ftp->fileListNode.filename, ftp->fileListNode.fileLengthBytes, ftp->currentOffset-bytesRead, bytesRead, done, systemAddress, setId);
1047
1048 dataBlocks[0]=(char*) outBitstream.GetData();
1049 lengths[0]=outBitstream.GetNumberOfBytesUsed();
1050 dataBlocks[1]=(char*) buff;
1051 lengths[1]=bytesRead;
1052 //rakPeerInterface->SendList(dataBlocks,lengths,2,ftp->packetPriority, RELIABLE_ORDERED, ftp->orderingChannel, ftp->systemAddress, false);
1053 char orderingChannel = ftp->orderingChannel;
1054 PacketPriority packetPriority = ftp->packetPriority;
1055
1056 // Mutex state: FileToPushRecipient (ftpr) has AddRef. fileToPushRecipientListMutex not locked.
1057 if (done)
1058 {
1059 // Done
1060 //unsigned short setId = ftp->setID;
1061 SLNet::OP_DELETE(ftp,_FILE_AND_LINE_);
1062
1064 if (ftpr->filesToPush.Size()==0)
1065 {
1067
1068 for (unsigned int flpcIndex=0; flpcIndex < fileListTransfer->fileListProgressCallbacks.Size(); flpcIndex++)
1069 fileListTransfer->fileListProgressCallbacks[flpcIndex]->OnFilePushesComplete(systemAddress, setId);
1070
1071 // Remove ftpr from fileToPushRecipientList
1072 fileListTransfer->RemoveFromList(ftpr);
1073 }
1074 else
1075 {
1077 }
1078 }
1079 else
1080 {
1082 ftpr->filesToPush.PushAtHead(ftp,0,_FILE_AND_LINE_);
1084 }
1085 // ftpr out of scope
1086 ftpr->Deref();
1087
1088 // 2/12/2012 Moved this line at after the if (done) block above.
1089 // See http://www.jenkinssoftware.com/forum/index.php?topic=4768.msg19738#msg19738
1090 fileListTransfer->SendListUnified(dataBlocks,lengths,2, packetPriority, RELIABLE_ORDERED, orderingChannel, systemAddress, false);
1091
1092 rakFree_Ex(buff, _FILE_AND_LINE_ );
1093 return 0;
1094 }
1095 else
1096 {
1097 ftpr->Deref();
1098 fileListTransfer->fileToPushRecipientListMutex.Lock();
1099 }
1100 }
1101
1102 fileListTransfer->fileToPushRecipientListMutex.Unlock();
1103
1104 return 0;
1105 }
1106 }
1107 void FileListTransfer::SendIRIToAddress(SystemAddress systemAddress, unsigned short inSetId)
1108 {
1109 ThreadData threadData;
1110 threadData.fileListTransfer=this;
1111 threadData.systemAddress=systemAddress;
1112 threadData.setId= inSetId;
1113
1114 if (threadPool.WasStarted())
1115 {
1116 threadPool.AddInput(SendIRIToAddressCB, threadData);
1117 }
1118 else
1119 {
1120 bool doesNothing;
1121 SendIRIToAddressCB(threadData, &doesNothing, 0);
1122 }
1123 }
1124 void FileListTransfer::OnReferencePushAck(Packet *packet)
1125 {
1126 SLNet::BitStream inBitStream(packet->data, packet->length, false);
1127 inBitStream.IgnoreBits(8);
1128 unsigned short curSetId;
1129 inBitStream.Read(curSetId);
1130 SendIRIToAddress(packet->systemAddress, curSetId);
1131 }
1132 void FileListTransfer::RemoveFromList(FileToPushRecipient *ftpr)
1133 {
1134 fileToPushRecipientListMutex.Lock();
1135 for (unsigned int i=0; i < fileToPushRecipientList.Size(); i++)
1136 {
1137 if (fileToPushRecipientList[i]==ftpr)
1138 {
1139 fileToPushRecipientList.RemoveAtIndex(i);
1140 // List no longer references
1141 ftpr->Deref();
1142 fileToPushRecipientListMutex.Unlock();
1143 return;
1144 }
1145 }
1146 fileToPushRecipientListMutex.Unlock();
1147 }
1148 unsigned int FileListTransfer::GetPendingFilesToAddress(SystemAddress recipient)
1149 {
1150 fileToPushRecipientListMutex.Lock();
1151 for (unsigned int i=0; i < fileToPushRecipientList.Size(); i++)
1152 {
1153 if (fileToPushRecipientList[i]->systemAddress==recipient)
1154 {
1155 unsigned int size = fileToPushRecipientList[i]->filesToPush.Size();
1156 fileToPushRecipientListMutex.Unlock();
1157 return size;
1158 }
1159 }
1160 fileToPushRecipientListMutex.Unlock();
1161
1162 return 0;
1163 }
1164
1165 #endif // _RAKNET_SUPPORT_*