bool CloudClient::Get(CloudQuery *keyQuery, RakNetGUID systemIdentifier) { SLNet::BitStream bsOut; bsOut.Write((MessageID)ID_CLOUD_GET_REQUEST); keyQuery->Serialize(true, &bsOut); bsOut.WriteCasted<uint16_t>(0); // Specific systems SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false); return true; }
void CloudClient::Release(DataStructures::List<CloudKey> &keys, RakNetGUID systemIdentifier) { SLNet::BitStream bsOut; bsOut.Write((MessageID)ID_CLOUD_RELEASE_REQUEST); RakAssert(keys.Size() < (uint16_t)-1 ); bsOut.WriteCasted<uint16_t>(keys.Size()); for (uint16_t i=0; i < keys.Size(); i++) { keys[i].Serialize(true,&bsOut); } SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false); }
PluginReceiveResult TwoWayAuthentication::OnHashedNonceAndPassword(Packet *packet) { SLNet::BitStream bsIn(packet->data, packet->length, false); bsIn.IgnoreBytes(sizeof(MessageID)*2); char remoteHashedNonceAndPw[HASHED_NONCE_AND_PW_LENGTH]; unsigned short requestId; bsIn.Read(requestId); SLNet::RakString passwordIdentifier; bsIn.Read(passwordIdentifier); bsIn.ReadAlignedBytes((unsigned char *) remoteHashedNonceAndPw,HASHED_NONCE_AND_PW_LENGTH); // Look up used nonce from requestId char usedNonce[TWO_WAY_AUTHENTICATION_NONCE_LENGTH]; if (nonceGenerator.GetNonceById(usedNonce, requestId, packet, true)==false) return RR_STOP_PROCESSING_AND_DEALLOCATE; DataStructures::HashIndex skhi = passwords.GetIndexOf(passwordIdentifier.C_String()); if (skhi.IsInvalid()==false) { char hashedThisNonceAndPw[HASHED_NONCE_AND_PW_LENGTH]; Hash(usedNonce, passwords.ItemAtIndex(skhi), hashedThisNonceAndPw); if (memcmp(hashedThisNonceAndPw, remoteHashedNonceAndPw,HASHED_NONCE_AND_PW_LENGTH)==0) { // Pass SLNet::BitStream bsOut; bsOut.Write((MessageID)ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_SUCCESS); bsOut.WriteAlignedBytes((const unsigned char*) usedNonce,TWO_WAY_AUTHENTICATION_NONCE_LENGTH); bsOut.WriteAlignedBytes((const unsigned char*) remoteHashedNonceAndPw,HASHED_NONCE_AND_PW_LENGTH); bsOut.Write(passwordIdentifier); SendUnified(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,packet,false); // Incoming success, modify packet header to tell user PushToUser(ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_SUCCESS, passwordIdentifier, packet); return RR_STOP_PROCESSING_AND_DEALLOCATE; } } // Incoming failure, modify arrived packet header to tell user packet->data[0]=(MessageID) ID_TWO_WAY_AUTHENTICATION_INCOMING_CHALLENGE_FAILURE; SLNet::BitStream bsOut; bsOut.Write((MessageID)ID_TWO_WAY_AUTHENTICATION_OUTGOING_CHALLENGE_FAILURE); bsOut.WriteAlignedBytes((const unsigned char*) usedNonce,TWO_WAY_AUTHENTICATION_NONCE_LENGTH); bsOut.WriteAlignedBytes((const unsigned char*) remoteHashedNonceAndPw,HASHED_NONCE_AND_PW_LENGTH); bsOut.Write(passwordIdentifier); SendUnified(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,packet,false); return RR_CONTINUE_PROCESSING; }
bool CloudClient::Get(CloudQuery *keyQuery, DataStructures::List<RakNetGUID> &specificSystems, RakNetGUID systemIdentifier) { SLNet::BitStream bsOut; bsOut.Write((MessageID)ID_CLOUD_GET_REQUEST); keyQuery->Serialize(true, &bsOut); bsOut.WriteCasted<uint16_t>(specificSystems.Size()); RakAssert(specificSystems.Size() < (uint16_t)-1 ); for (uint16_t i=0; i < specificSystems.Size(); i++) { bsOut.Write(specificSystems[i]); } SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false); return true; }
void CloudClient::Post(CloudKey *cloudKey, const unsigned char *data, uint32_t dataLengthBytes, RakNetGUID systemIdentifier) { RakAssert(cloudKey); SLNet::BitStream bsOut; bsOut.Write((MessageID)ID_CLOUD_POST_REQUEST); cloudKey->Serialize(true,&bsOut); if (data==0) dataLengthBytes=0; bsOut.Write(dataLengthBytes); if (dataLengthBytes>0) bsOut.WriteAlignedBytes((const unsigned char*) data, dataLengthBytes); SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false); }
void TwoWayAuthentication::OnNonceRequest(Packet *packet) { SLNet::BitStream bsIn(packet->data, packet->length, false); bsIn.IgnoreBytes(sizeof(MessageID)*2); char nonce[TWO_WAY_AUTHENTICATION_NONCE_LENGTH]; unsigned short requestId; nonceGenerator.GetNonce(nonce,&requestId,packet); SLNet::BitStream bsOut; bsOut.Write((MessageID)ID_TWO_WAY_AUTHENTICATION_NEGOTIATION); bsOut.Write((MessageID)ID_NONCE_REPLY); bsOut.Write(requestId); bsOut.WriteAlignedBytes((const unsigned char*) nonce,TWO_WAY_AUTHENTICATION_NONCE_LENGTH); SendUnified(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,packet,false); }
void CloudClient::Unsubscribe(DataStructures::List<CloudKey> &keys, DataStructures::List<RakNetGUID> &specificSystems, RakNetGUID systemIdentifier) { SLNet::BitStream bsOut; bsOut.Write((MessageID)ID_CLOUD_UNSUBSCRIBE_REQUEST); RakAssert(keys.Size() < (uint16_t)-1 ); bsOut.WriteCasted<uint16_t>(keys.Size()); for (uint16_t i=0; i < keys.Size(); i++) { keys[i].Serialize(true,&bsOut); } bsOut.WriteCasted<uint16_t>(specificSystems.Size()); RakAssert(specificSystems.Size() < (uint16_t)-1 ); for (uint16_t i=0; i < specificSystems.Size(); i++) { bsOut.Write(specificSystems[i]); } SendUnified(&bsOut, HIGH_PRIORITY, RELIABLE_ORDERED, 0, systemIdentifier, false); }
bool TwoWayAuthentication::Challenge(SLNet::RakString identifier, AddressOrGUID remoteSystem) { DataStructures::HashIndex skhi = passwords.GetIndexOf(identifier.C_String()); if (skhi.IsInvalid()) return false; SLNet::BitStream bsOut; bsOut.Write((MessageID)ID_TWO_WAY_AUTHENTICATION_NEGOTIATION); bsOut.Write((MessageID)ID_NONCE_REQUEST); SendUnified(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,remoteSystem,false); PendingChallenge pc; pc.identifier=identifier; pc.remoteSystem=remoteSystem; pc.time= SLNet::GetTime(); pc.sentHash=false; outgoingChallenges.Push(pc,_FILE_AND_LINE_); return true; }
void TwoWayAuthentication::PushToUser(MessageID messageId, SLNet::RakString password, SLNet::AddressOrGUID remoteSystem) { SLNet::BitStream output; output.Write(messageId); if (password.IsEmpty()==false) output.Write(password); Packet *p = AllocatePacketUnified(output.GetNumberOfBytesUsed()); p->systemAddress=remoteSystem.systemAddress; p->systemAddress.systemIndex=(SystemIndex)-1; p->guid=remoteSystem.rakNetGuid; p->wasGeneratedLocally=true; memcpy(p->data, output.GetData(), output.GetNumberOfBytesUsed()); rakPeerInterface->PushBackPacket(p, true); }
void TwoWayAuthentication::OnNonceReply(Packet *packet) { SLNet::BitStream bsIn(packet->data, packet->length, false); bsIn.IgnoreBytes(sizeof(MessageID)*2); char thierNonce[TWO_WAY_AUTHENTICATION_NONCE_LENGTH]; unsigned short requestId; bsIn.Read(requestId); bsIn.ReadAlignedBytes((unsigned char *) thierNonce,TWO_WAY_AUTHENTICATION_NONCE_LENGTH); // Lookup one of the negotiations for this guid/system address AddressOrGUID aog(packet); unsigned int i; for (i=0; i < outgoingChallenges.Size(); i++) { if (outgoingChallenges[i].remoteSystem==aog && outgoingChallenges[i].sentHash==false) { outgoingChallenges[i].sentHash=true; // Get the password for this identifier DataStructures::HashIndex skhi = passwords.GetIndexOf(outgoingChallenges[i].identifier.C_String()); if (skhi.IsInvalid()==false) { SLNet::RakString password = passwords.ItemAtIndex(skhi); // Hash their nonce with password and reply char hashedNonceAndPw[HASHED_NONCE_AND_PW_LENGTH]; Hash(thierNonce, password, hashedNonceAndPw); // Send SLNet::BitStream bsOut; bsOut.Write((MessageID)ID_TWO_WAY_AUTHENTICATION_NEGOTIATION); bsOut.Write((MessageID)ID_HASHED_NONCE_AND_PASSWORD); bsOut.Write(requestId); bsOut.Write(outgoingChallenges[i].identifier); // Identifier helps the other system lookup the password quickly. bsOut.WriteAlignedBytes((const unsigned char*) hashedNonceAndPw,HASHED_NONCE_AND_PW_LENGTH); SendUnified(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,packet,false); } return; } } }
int SendIRIToAddressCB(FileListTransfer::ThreadData threadData, bool *returnOutput, void* perThreadData) { (void) perThreadData; FileListTransfer *fileListTransfer = threadData.fileListTransfer; SystemAddress systemAddress = threadData.systemAddress; unsigned short setId = threadData.setId; *returnOutput=false; // Was previously using GetStatistics to get outgoing buffer size, but TCP with UnifiedSend doesn't have this unsigned int bytesRead; const char *dataBlocks[2]; int lengths[2]; unsigned int smallFileTotalSize=0; SLNet::BitStream outBitstream; unsigned int ftpIndex; fileListTransfer->fileToPushRecipientListMutex.Lock(); for (ftpIndex=0; ftpIndex < fileListTransfer->fileToPushRecipientList.Size(); ftpIndex++) { FileListTransfer::FileToPushRecipient *ftpr = fileListTransfer->fileToPushRecipientList[ftpIndex]; // Referenced by both ftpr and list ftpr->AddRef(); fileListTransfer->fileToPushRecipientListMutex.Unlock(); if (ftpr->systemAddress==systemAddress && ftpr->setId==setId) { FileListTransfer::FileToPush *ftp; ////ftpr->filesToPushMutex.Lock(); ftp = ftpr->filesToPush.Pop(); ////ftpr->filesToPushMutex.Unlock(); // Read and send chunk. If done, delete at this index void *buff = rakMalloc_Ex(ftp->chunkSize, _FILE_AND_LINE_); if (buff==0) { ////ftpr->filesToPushMutex.Lock(); ftpr->filesToPush.PushAtHead(ftp,0,_FILE_AND_LINE_); ////ftpr->filesToPushMutex.Unlock(); ftpr->Deref(); notifyOutOfMemory(_FILE_AND_LINE_); return 0; } // Read the next file chunk bytesRead=ftp->incrementalReadInterface->GetFilePart(ftp->fileListNode.fullPathToFile, ftp->currentOffset, ftp->chunkSize, buff, ftp->fileListNode.context); bool done = ftp->fileListNode.dataLengthBytes == ftp->currentOffset+bytesRead; while (done && ftp->currentOffset==0 && smallFileTotalSize<ftp->chunkSize) { ////ftpr->filesToPushMutex.Lock(); // 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 if (ftpr->filesToPush.Size()<2) { ////ftpr->filesToPushMutex.Unlock(); break; } ////ftpr->filesToPushMutex.Unlock(); // 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 outBitstream.Reset(); outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_FILE); // outBitstream.Write(ftp->fileListNode.context); outBitstream << ftp->fileListNode.context; outBitstream.Write(setId); StringCompressor::Instance()->EncodeString(ftp->fileListNode.filename, 512, &outBitstream); outBitstream.WriteCompressed(ftp->setIndex); outBitstream.WriteCompressed(ftp->fileListNode.dataLengthBytes); // Original length in bytes outBitstream.AlignWriteToByteBoundary(); dataBlocks[0]=(char*) outBitstream.GetData(); lengths[0]=outBitstream.GetNumberOfBytesUsed(); dataBlocks[1]=(const char*) buff; lengths[1]=bytesRead; fileListTransfer->SendListUnified(dataBlocks,lengths,2,ftp->packetPriority, RELIABLE_ORDERED, ftp->orderingChannel, systemAddress, false); // LWS : fixed freed pointer reference // unsigned int chunkSize = ftp->chunkSize; SLNet::OP_DELETE(ftp,_FILE_AND_LINE_); smallFileTotalSize+=bytesRead; //done = bytesRead!=ftp->chunkSize; ////ftpr->filesToPushMutex.Lock(); ftp = ftpr->filesToPush.Pop(); ////ftpr->filesToPushMutex.Unlock(); bytesRead=ftp->incrementalReadInterface->GetFilePart(ftp->fileListNode.fullPathToFile, ftp->currentOffset, ftp->chunkSize, buff, ftp->fileListNode.context); done = ftp->fileListNode.dataLengthBytes == ftp->currentOffset+bytesRead; } outBitstream.Reset(); outBitstream.Write((MessageID)ID_FILE_LIST_REFERENCE_PUSH); // outBitstream.Write(ftp->fileListNode.context); outBitstream << ftp->fileListNode.context; outBitstream.Write(setId); StringCompressor::Instance()->EncodeString(ftp->fileListNode.filename, 512, &outBitstream); outBitstream.WriteCompressed(ftp->setIndex); outBitstream.WriteCompressed(ftp->fileListNode.dataLengthBytes); // Original length in bytes outBitstream.WriteCompressed(ftp->currentOffset); ftp->currentOffset+=bytesRead; outBitstream.WriteCompressed(bytesRead); outBitstream.Write(done); for (unsigned int flpcIndex=0; flpcIndex < fileListTransfer->fileListProgressCallbacks.Size(); flpcIndex++) fileListTransfer->fileListProgressCallbacks[flpcIndex]->OnFilePush(ftp->fileListNode.filename, ftp->fileListNode.fileLengthBytes, ftp->currentOffset-bytesRead, bytesRead, done, systemAddress, setId); dataBlocks[0]=(char*) outBitstream.GetData(); lengths[0]=outBitstream.GetNumberOfBytesUsed(); dataBlocks[1]=(char*) buff; lengths[1]=bytesRead; //rakPeerInterface->SendList(dataBlocks,lengths,2,ftp->packetPriority, RELIABLE_ORDERED, ftp->orderingChannel, ftp->systemAddress, false); char orderingChannel = ftp->orderingChannel; PacketPriority packetPriority = ftp->packetPriority; // Mutex state: FileToPushRecipient (ftpr) has AddRef. fileToPushRecipientListMutex not locked. if (done) { // Done //unsigned short setId = ftp->setID; SLNet::OP_DELETE(ftp,_FILE_AND_LINE_); ////ftpr->filesToPushMutex.Lock(); if (ftpr->filesToPush.Size()==0) { ////ftpr->filesToPushMutex.Unlock(); for (unsigned int flpcIndex=0; flpcIndex < fileListTransfer->fileListProgressCallbacks.Size(); flpcIndex++) fileListTransfer->fileListProgressCallbacks[flpcIndex]->OnFilePushesComplete(systemAddress, setId); // Remove ftpr from fileToPushRecipientList fileListTransfer->RemoveFromList(ftpr); } else { ////ftpr->filesToPushMutex.Unlock(); } } else { ////ftpr->filesToPushMutex.Lock(); ftpr->filesToPush.PushAtHead(ftp,0,_FILE_AND_LINE_); ////ftpr->filesToPushMutex.Unlock(); } // ftpr out of scope ftpr->Deref(); // 2/12/2012 Moved this line at after the if (done) block above. // See http://www.jenkinssoftware.com/forum/index.php?topic=4768.msg19738#msg19738 fileListTransfer->SendListUnified(dataBlocks,lengths,2, packetPriority, RELIABLE_ORDERED, orderingChannel, systemAddress, false); rakFree_Ex(buff, _FILE_AND_LINE_ ); return 0; } else { ftpr->Deref(); fileListTransfer->fileToPushRecipientListMutex.Lock(); } } fileListTransfer->fileToPushRecipientListMutex.Unlock(); return 0; }
void FileListTransfer::OnReferencePush(Packet *packet, bool isTheFullFile) { SLNet::BitStream refPushAck; if (isTheFullFile==false) { // 12/23/09 Why do I care about ID_DOWNLOAD_PROGRESS for reference pushes? // 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. // return; } FileListTransferCBInterface::OnFileStruct onFileStruct; SLNet::BitStream inBitStream(packet->data, packet->length, false); inBitStream.IgnoreBits(8); unsigned int partCount=0; unsigned int partTotal=1; unsigned int partLength=0; onFileStruct.fileData=0; if (isTheFullFile==false) { // Disable endian swapping on reading this, as it's generated locally in ReliabilityLayer.cpp inBitStream.ReadBits( (unsigned char* ) &partCount, BYTES_TO_BITS(sizeof(partCount)), true ); inBitStream.ReadBits( (unsigned char* ) &partTotal, BYTES_TO_BITS(sizeof(partTotal)), true ); inBitStream.ReadBits( (unsigned char* ) &partLength, BYTES_TO_BITS(sizeof(partLength)), true ); inBitStream.IgnoreBits(8); // The header is appended to every chunk, which we continue to read after this statement flrMemoryBlock } inBitStream >> onFileStruct.context; inBitStream.Read(onFileStruct.setID); // This is not a progress notification, it is actually the entire packet if (isTheFullFile==true) { refPushAck.Write((MessageID)ID_FILE_LIST_REFERENCE_PUSH_ACK); refPushAck.Write(onFileStruct.setID); SendUnified(&refPushAck,HIGH_PRIORITY, RELIABLE, 0, packet->systemAddress, false); } // inBitStream.Read(onFileStruct.context); FileListReceiver *fileListReceiver; if (fileListReceivers.Has(onFileStruct.setID)==false) { return; } fileListReceiver=fileListReceivers.Get(onFileStruct.setID); if (fileListReceiver->allowedSender!=packet->systemAddress) { #ifdef _DEBUG RakAssert(0); #endif return; } #ifdef _DEBUG RakAssert(fileListReceiver->gotSetHeader==true); #endif if (StringCompressor::Instance()->DecodeString(onFileStruct.fileName, 512, &inBitStream)==false) { #ifdef _DEBUG RakAssert(0); #endif return; } inBitStream.ReadCompressed(onFileStruct.fileIndex); inBitStream.ReadCompressed(onFileStruct.byteLengthOfThisFile); unsigned int offset; unsigned int chunkLength; inBitStream.ReadCompressed(offset); inBitStream.ReadCompressed(chunkLength); bool lastChunk=false; inBitStream.Read(lastChunk); bool finished = lastChunk && isTheFullFile; if (isTheFullFile==false) fileListReceiver->partLength=partLength; FLR_MemoryBlock mb; if (fileListReceiver->pushedFiles.Has(onFileStruct.fileIndex)==false) { if (onFileStruct.byteLengthOfThisFile <= SLNET_MAX_RETRIEVABLE_FILESIZE) mb.flrMemoryBlock = (char*)rakMalloc_Ex(onFileStruct.byteLengthOfThisFile, _FILE_AND_LINE_); else mb.flrMemoryBlock = nullptr; fileListReceiver->pushedFiles.SetNew(onFileStruct.fileIndex, mb); } else { mb=fileListReceiver->pushedFiles.Get(onFileStruct.fileIndex); } unsigned int unreadBits = inBitStream.GetNumberOfUnreadBits(); unsigned int unreadBytes = BITS_TO_BYTES(unreadBits); unsigned int amountToRead; if (isTheFullFile) amountToRead=chunkLength; else amountToRead=unreadBytes; inBitStream.AlignReadToByteBoundary(); FileListTransferCBInterface::FileProgressStruct fps; if (isTheFullFile) { if (mb.flrMemoryBlock) { // Either the very first block, or a subsequent block and allocateIrIDataChunkAutomatically was true for the first block memcpy(mb.flrMemoryBlock+offset, inBitStream.GetData()+BITS_TO_BYTES(inBitStream.GetReadOffset()), amountToRead); fps.iriDataChunk=mb.flrMemoryBlock+offset; } else { // In here mb.flrMemoryBlock is null // This means the first block explicitly deallocated the memory, and no blocks will be permanently held by RakNet fps.iriDataChunk=(char*) inBitStream.GetData()+BITS_TO_BYTES(inBitStream.GetReadOffset()); } onFileStruct.bytesDownloadedForThisFile=offset+chunkLength; fileListReceiver->setTotalDownloadedLength+=chunkLength; onFileStruct.bytesDownloadedForThisSet=fileListReceiver->setTotalDownloadedLength; } else { onFileStruct.bytesDownloadedForThisFile=offset+partLength*partCount; onFileStruct.bytesDownloadedForThisSet=fileListReceiver->setTotalDownloadedLength+partCount*partLength; fps.iriDataChunk=(char*) inBitStream.GetData()+BITS_TO_BYTES(inBitStream.GetReadOffset()); } onFileStruct.numberOfFilesInThisSet=fileListReceiver->setCount; // onFileStruct.setTotalCompressedTransmissionLength=fileListReceiver->setTotalCompressedTransmissionLength; onFileStruct.byteLengthOfThisSet=fileListReceiver->setTotalFinalLength; // Note: mb.flrMemoryBlock may be null here onFileStruct.fileData=mb.flrMemoryBlock; onFileStruct.senderSystemAddress=packet->systemAddress; onFileStruct.senderGuid=packet->guid; unsigned int totalNotifications; unsigned int currentNotificationIndex; if (chunkLength==0 || chunkLength==onFileStruct.byteLengthOfThisFile) totalNotifications=1; else totalNotifications = onFileStruct.byteLengthOfThisFile / chunkLength + 1; if (chunkLength==0) currentNotificationIndex = 0; else currentNotificationIndex = offset / chunkLength; fps.onFileStruct=&onFileStruct; fps.partCount=currentNotificationIndex; fps.partTotal=totalNotifications; fps.dataChunkLength=amountToRead; fps.firstDataChunk=mb.flrMemoryBlock; fps.allocateIrIDataChunkAutomatically=true; fps.onFileStruct->fileData=mb.flrMemoryBlock; fps.iriWriteOffset=offset; fps.senderSystemAddress=packet->systemAddress; fps.senderGuid=packet->guid; if (finished) { char *oldFileData=fps.onFileStruct->fileData; if (fps.partCount==0) fps.firstDataChunk=fps.iriDataChunk; if (fps.partTotal==1) fps.onFileStruct->fileData=fps.iriDataChunk; fileListReceiver->downloadHandler->OnFileProgress(&fps); // Incremental read interface sent us a file chunk // This is the last file chunk we were waiting for to consider the file done if (fileListReceiver->downloadHandler->OnFile(&onFileStruct)) rakFree_Ex(oldFileData, _FILE_AND_LINE_ ); fileListReceiver->pushedFiles.Delete(onFileStruct.fileIndex); fileListReceiver->filesReceived++; // If this set is done, free the memory for it. if ((int) fileListReceiver->setCount==fileListReceiver->filesReceived) { FileListTransferCBInterface::DownloadCompleteStruct dcs; dcs.setID=fileListReceiver->setID; dcs.numberOfFilesInThisSet=fileListReceiver->setCount; dcs.byteLengthOfThisSet=fileListReceiver->setTotalFinalLength; dcs.senderSystemAddress=packet->systemAddress; dcs.senderGuid=packet->guid; if (fileListReceiver->downloadHandler->OnDownloadComplete(&dcs)==false) { fileListReceiver->downloadHandler->OnDereference(); fileListReceivers.Delete(onFileStruct.setID); if (fileListReceiver->deleteDownloadHandler) SLNet::OP_DELETE(fileListReceiver->downloadHandler, _FILE_AND_LINE_); SLNet::OP_DELETE(fileListReceiver, _FILE_AND_LINE_); } } } else { if (isTheFullFile) { // 12/23/09 Don't use OnReferencePush anymore, just use OnFileProgress fileListReceiver->downloadHandler->OnFileProgress(&fps); if (fps.allocateIrIDataChunkAutomatically==false) { rakFree_Ex(fileListReceiver->pushedFiles.Get(onFileStruct.fileIndex).flrMemoryBlock, _FILE_AND_LINE_ ); fileListReceiver->pushedFiles.Get(onFileStruct.fileIndex).flrMemoryBlock=0; } } else { // This is a download progress notification for a file chunk using incremental read interface // We don't have all the data for this chunk yet totalNotifications = onFileStruct.byteLengthOfThisFile / fileListReceiver->partLength + 1; if (isTheFullFile==false) currentNotificationIndex = (offset+partCount*fileListReceiver->partLength) / fileListReceiver->partLength ; else currentNotificationIndex = (offset+chunkLength) / fileListReceiver->partLength ; unreadBytes = onFileStruct.byteLengthOfThisFile - ((currentNotificationIndex+1) * fileListReceiver->partLength); fps.partCount=currentNotificationIndex; fps.partTotal=totalNotifications; // 2/19/2013 Why was this check here? It prevent smaller progress notifications // if (rakPeerInterface) { // Thus chunk is incomplete fps.iriDataChunk=0; fileListReceiver->downloadHandler->OnFileProgress(&fps); } } } }
void FileListTransfer::Send(FileList *fileList, SLNet::RakPeerInterface *rakPeer, SystemAddress recipient, unsigned short setID, PacketPriority priority, char orderingChannel, IncrementalReadInterface *_incrementalReadInterface, unsigned int _chunkSize) { for (unsigned int flpcIndex=0; flpcIndex < fileListProgressCallbacks.Size(); flpcIndex++) fileList->AddCallback(fileListProgressCallbacks[flpcIndex]); unsigned int i, totalLength; SLNet::BitStream outBitstream; bool sendReference; const char *dataBlocks[2]; int lengths[2]; totalLength=0; for (i=0; i < fileList->fileList.Size(); i++) { const FileListNode &fileListNode = fileList->fileList[i]; totalLength+=fileListNode.dataLengthBytes; } // Write the chunk header, which contains the frequency table, the total number of files, and the total number of bytes bool anythingToWrite; outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_HEADER); outBitstream.Write(setID); anythingToWrite=fileList->fileList.Size()>0; outBitstream.Write(anythingToWrite); if (anythingToWrite) { outBitstream.WriteCompressed(fileList->fileList.Size()); outBitstream.WriteCompressed(totalLength); if (rakPeer) rakPeer->Send(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false); else SendUnified(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false); DataStructures::Queue<FileToPush*> filesToPush; for (i=0; i < fileList->fileList.Size(); i++) { sendReference = fileList->fileList[i].isAReference && _incrementalReadInterface!=0; if (sendReference) { FileToPush *fileToPush = SLNet::OP_NEW<FileToPush>(_FILE_AND_LINE_); fileToPush->fileListNode.context=fileList->fileList[i].context; fileToPush->setIndex=i; fileToPush->fileListNode.filename=fileList->fileList[i].filename; fileToPush->fileListNode.fullPathToFile=fileList->fileList[i].fullPathToFile; fileToPush->fileListNode.fileLengthBytes=fileList->fileList[i].fileLengthBytes; fileToPush->fileListNode.dataLengthBytes=fileList->fileList[i].dataLengthBytes; // fileToPush->systemAddress=recipient; //fileToPush->setID=setID; fileToPush->packetPriority=priority; fileToPush->orderingChannel=orderingChannel; fileToPush->currentOffset=0; fileToPush->incrementalReadInterface=_incrementalReadInterface; fileToPush->chunkSize=_chunkSize; filesToPush.Push(fileToPush,_FILE_AND_LINE_); } else { outBitstream.Reset(); outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_FILE); outBitstream << fileList->fileList[i].context; // outBitstream.Write(fileList->fileList[i].context); outBitstream.Write(setID); StringCompressor::Instance()->EncodeString(fileList->fileList[i].filename, 512, &outBitstream); outBitstream.WriteCompressed(i); outBitstream.WriteCompressed(fileList->fileList[i].dataLengthBytes); // Original length in bytes outBitstream.AlignWriteToByteBoundary(); dataBlocks[0]=(char*) outBitstream.GetData(); lengths[0]=outBitstream.GetNumberOfBytesUsed(); dataBlocks[1]=fileList->fileList[i].data; lengths[1]=fileList->fileList[i].dataLengthBytes; SendListUnified(dataBlocks,lengths,2,priority, RELIABLE_ORDERED, orderingChannel, recipient, false); } } if (filesToPush.IsEmpty()==false) { FileToPushRecipient *ftpr; fileToPushRecipientListMutex.Lock(); for (i=0; i < fileToPushRecipientList.Size(); i++) { if (fileToPushRecipientList[i]->systemAddress==recipient && fileToPushRecipientList[i]->setId==setId) { // ftpr=fileToPushRecipientList[i]; // ftpr->AddRef(); // break; RakAssert("setId already in use for this recipient" && 0); } } fileToPushRecipientListMutex.Unlock(); //if (ftpr==0) //{ ftpr = SLNet::OP_NEW<FileToPushRecipient>(_FILE_AND_LINE_); ftpr->systemAddress=recipient; ftpr->setId=setID; ftpr->refCount=2; // Allocated and in the list fileToPushRecipientList.Push(ftpr, _FILE_AND_LINE_); //} while (filesToPush.IsEmpty()==false) { ////ftpr->filesToPushMutex.Lock(); ftpr->filesToPush.Push(filesToPush.Pop(), _FILE_AND_LINE_); ////ftpr->filesToPushMutex.Unlock(); } // ftpr out of scope ftpr->Deref(); SendIRIToAddress(recipient, setID); return; } else { for (unsigned int flpcIndex=0; flpcIndex < fileListProgressCallbacks.Size(); flpcIndex++) fileListProgressCallbacks[flpcIndex]->OnFilePushesComplete(recipient, setID); } } else { for (unsigned int flpcIndex=0; flpcIndex < fileListProgressCallbacks.Size(); flpcIndex++) fileListProgressCallbacks[flpcIndex]->OnFilePushesComplete(recipient, setID); if (rakPeer) rakPeer->Send(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false); else SendUnified(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false); } }