Esempio n. 1
0
void RPC4::Call( const char* uniqueID, RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast )
{
	RakNet::BitStream out;
	out.Write((MessageID) ID_RPC_PLUGIN);
	out.Write((MessageID) ID_RPC4_CALL);
	out.WriteCompressed(uniqueID);
	out.Write(false); // Nonblocking
	if (bitStream)
	{
		bitStream->ResetReadPointer();
        out.AlignWriteToByteBoundary();
		out.Write(bitStream);
	}
	SendUnified(&out,priority,reliability,orderingChannel,systemIdentifier,broadcast);
}
Esempio n. 2
0
void RPC4::Signal(const char *sharedIdentifier, RakNet::BitStream *bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast, bool invokeLocal)
{
	RakNet::BitStream out;
	out.Write((MessageID) ID_RPC_PLUGIN);
	out.Write((MessageID) ID_RPC4_SIGNAL);
	out.WriteCompressed(sharedIdentifier);
	if (bitStream)
	{
		bitStream->ResetReadPointer();
		out.AlignWriteToByteBoundary();
		out.Write(bitStream);
	}
	SendUnified(&out,priority,reliability,orderingChannel,systemIdentifier,broadcast);

	if (invokeLocal)
	{
		DataStructures::HashIndex functionIndex;
		functionIndex = localSlots.GetIndexOf(sharedIdentifier);
		if (functionIndex.IsInvalid())
			return;
		
		Packet p;
		p.guid=rakPeerInterface->GetMyGUID();
		p.systemAddress=rakPeerInterface->GetMyBoundAddress(0);
		p.wasGeneratedLocally=true;
		RakNet::BitStream *bsptr, bstemp;
		if (bitStream)
		{
			bitStream->ResetReadPointer();
			p.length=bitStream->GetNumberOfBytesUsed();
			p.bitSize=bitStream->GetNumberOfBitsUsed();
			bsptr=bitStream;
		}
		else
		{
			p.length=0;
			p.bitSize=0;
			bsptr=&bstemp;
		}
		InvokeSignal(functionIndex, bsptr, &p);
	}
}
Esempio n. 3
0
PluginReceiveResult RPC4::OnReceive(Packet *packet)
{
	if (packet->data[0]==ID_RPC_PLUGIN)
	{
		RakNet::BitStream bsIn(packet->data,packet->length,false);
		bsIn.IgnoreBytes(2);

		if (packet->data[1]==ID_RPC4_CALL)
		{
			RakNet::RakString functionName;
			bsIn.ReadCompressed(functionName);
			bool isBlocking;
			bsIn.Read(isBlocking);
			if (isBlocking==false)
			{
				DataStructures::HashIndex skhi = registeredNonblockingFunctions.GetIndexOf(functionName.C_String());
				if (skhi.IsInvalid())
				{
					RakNet::BitStream bsOut;
					bsOut.Write((unsigned char) ID_RPC_REMOTE_ERROR);
					bsOut.Write((unsigned char) RPC_ERROR_FUNCTION_NOT_REGISTERED);
					bsOut.Write(functionName.C_String(),(unsigned int) functionName.GetLength()+1);
					SendUnified(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,packet->systemAddress,false);
					return RR_STOP_PROCESSING_AND_DEALLOCATE;
				}

				void ( *fp ) ( RakNet::BitStream *, Packet * );
				fp = registeredNonblockingFunctions.ItemAtIndex(skhi);
                bsIn.AlignReadToByteBoundary();
				fp(&bsIn,packet);
			}
			else
			{
				DataStructures::HashIndex skhi = registeredBlockingFunctions.GetIndexOf(functionName.C_String());
				if (skhi.IsInvalid())
				{
					RakNet::BitStream bsOut;
					bsOut.Write((unsigned char) ID_RPC_REMOTE_ERROR);
					bsOut.Write((unsigned char) RPC_ERROR_FUNCTION_NOT_REGISTERED);
					bsOut.Write(functionName.C_String(),(unsigned int) functionName.GetLength()+1);
					SendUnified(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,packet->systemAddress,false);
					return RR_STOP_PROCESSING_AND_DEALLOCATE;
				}

				void ( *fp ) ( RakNet::BitStream *, RakNet::BitStream *, Packet * );
				fp = registeredBlockingFunctions.ItemAtIndex(skhi);
				RakNet::BitStream returnData;
                bsIn.AlignReadToByteBoundary();
				fp(&bsIn, &returnData, packet);

				RakNet::BitStream out;
				out.Write((MessageID) ID_RPC_PLUGIN);
				out.Write((MessageID) ID_RPC4_RETURN);
				returnData.ResetReadPointer();
                out.AlignWriteToByteBoundary();
				out.Write(returnData);
				SendUnified(&out,IMMEDIATE_PRIORITY,RELIABLE_ORDERED,0,packet->systemAddress,false);
			}
		}
		else
		{
			RakAssert(packet->data[1]==ID_RPC4_RETURN);
			blockingReturnValue.Reset();
			blockingReturnValue.Read(bsIn);
			gotBlockingReturnValue=true;
		}
		
		return RR_STOP_PROCESSING_AND_DEALLOCATE;
	}

	bool objectExists;
	unsigned int index, index2;
	index = localCallbacks.GetIndexFromKey(packet->data[0],&objectExists);
	if (objectExists)
	{
		LocalCallback *lc;
		lc = localCallbacks[index];
		for (index2=0; index2 < lc->functions.Size(); index2++)
		{
			RakNet::BitStream bsIn(packet->data, packet->length, false);

			DataStructures::HashIndex skhi = registeredNonblockingFunctions.GetIndexOf(lc->functions[index2].C_String());
			if (skhi.IsInvalid()==false)
			{
				void ( *fp ) ( RakNet::BitStream *, Packet * );
				fp = registeredNonblockingFunctions.ItemAtIndex(skhi);
                bsIn.AlignReadToByteBoundary();
				fp(&bsIn,packet);
			}		
		}
	}

	return RR_CONTINUE_PROCESSING;
}
Esempio n. 4
0
bool RPC4::CallBlocking( const char* uniqueID, RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, RakNet::BitStream *returnData )
{
	RakNet::BitStream out;
	out.Write((MessageID) ID_RPC_PLUGIN);
	out.Write((MessageID) ID_RPC4_CALL);
	out.WriteCompressed(uniqueID);
	out.Write(true); // Blocking
	if (bitStream)
	{
		bitStream->ResetReadPointer();
        out.AlignWriteToByteBoundary();
		out.Write(bitStream);
	}
	RakAssert(returnData);
	RakAssert(rakPeerInterface);
	ConnectionState cs;
	cs = rakPeerInterface->GetConnectionState(systemIdentifier);
	if (cs!=IS_CONNECTED && cs!=IS_LOOPBACK)
		return false;

	SendUnified(&out,priority,reliability,orderingChannel,systemIdentifier,false);

	returnData->Reset();
	blockingReturnValue.Reset();
	gotBlockingReturnValue=false;
	Packet *packet;
	DataStructures::Queue<Packet*> packetQueue;
	while (gotBlockingReturnValue==false)
	{
		// TODO - block, filter until gotBlockingReturnValue==true or ID_CONNECTION_LOST or ID_DISCONNECTION_NOTIFICXATION or ID_RPC_REMOTE_ERROR/RPC_ERROR_FUNCTION_NOT_REGISTERED
		RakSleep(30);

		packet=rakPeerInterface->Receive();

		if (packet)
		{
			if (
				(packet->data[0]==ID_CONNECTION_LOST || packet->data[0]==ID_DISCONNECTION_NOTIFICATION) &&
				((systemIdentifier.rakNetGuid!=UNASSIGNED_RAKNET_GUID && packet->guid==systemIdentifier.rakNetGuid) ||
				(systemIdentifier.systemAddress!=UNASSIGNED_SYSTEM_ADDRESS && packet->systemAddress==systemIdentifier.systemAddress))
				)
			{
				// Push back to head in reverse order
				rakPeerInterface->PushBackPacket(packet,true);
				while (packetQueue.Size())
					rakPeerInterface->PushBackPacket(packetQueue.Pop(),true);
				return false;
			}
			else if (packet->data[0]==ID_RPC_REMOTE_ERROR && packet->data[1]==RPC_ERROR_FUNCTION_NOT_REGISTERED)
			{
				RakNet::RakString functionName;
				RakNet::BitStream bsIn(packet->data,packet->length,false);
				bsIn.IgnoreBytes(2);
				bsIn.Read(functionName);
				if (functionName==uniqueID)
				{
					// Push back to head in reverse order
					rakPeerInterface->PushBackPacket(packet,true);
					while (packetQueue.Size())
						rakPeerInterface->PushBackPacket(packetQueue.Pop(),true);
					return false;
				}
				else
				{
					packetQueue.PushAtHead(packet,0,_FILE_AND_LINE_);
				}
			}
			else
			{
				packetQueue.PushAtHead(packet,0,_FILE_AND_LINE_);
			}
		}
	}

	returnData->Read(blockingReturnValue);
	return true;
}
Esempio n. 5
0
void RPC4::CallLoopback( const char* uniqueID, RakNet::BitStream * bitStream )
{
	Packet *p=0;

	DataStructures::HashIndex skhi = registeredNonblockingFunctions.GetIndexOf(uniqueID);

	if (skhi.IsInvalid()==true)
	{
		if (rakPeerInterface) 
			p=AllocatePacketUnified(sizeof(MessageID)+sizeof(unsigned char)+(unsigned int) strlen(uniqueID)+1);
#if _RAKNET_SUPPORT_PacketizedTCP==1 && _RAKNET_SUPPORT_TCPInterface==1
		else
			p=packetizedTCP->AllocatePacket(sizeof(MessageID)+sizeof(unsigned char)+(unsigned int) strlen(uniqueID)+1);
#endif

		if (rakPeerInterface)
			p->guid=rakPeerInterface->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS);
#if _RAKNET_SUPPORT_PacketizedTCP==1 && _RAKNET_SUPPORT_TCPInterface==1
		else
			p->guid=UNASSIGNED_RAKNET_GUID;
#endif

		p->systemAddress=UNASSIGNED_SYSTEM_ADDRESS;
		p->systemAddress.systemIndex=(SystemIndex)-1;
		p->data[0]=ID_RPC_REMOTE_ERROR;
		p->data[1]=RPC_ERROR_FUNCTION_NOT_REGISTERED;
		strcpy((char*) p->data+2, uniqueID);
		
		PushBackPacketUnified(p,false);

		return;
	}

	RakNet::BitStream out;
	out.Write((MessageID) ID_RPC_PLUGIN);
	out.Write((MessageID) ID_RPC4_CALL);
	out.WriteCompressed(uniqueID);
	out.Write(false); // nonblocking
	if (bitStream)
	{
		bitStream->ResetReadPointer();
        out.AlignWriteToByteBoundary();
		out.Write(bitStream);
	}
	if (rakPeerInterface) 
		p=AllocatePacketUnified(out.GetNumberOfBytesUsed());
#if _RAKNET_SUPPORT_PacketizedTCP==1 && _RAKNET_SUPPORT_TCPInterface==1
	else
		p=packetizedTCP->AllocatePacket(out.GetNumberOfBytesUsed());
#endif

	if (rakPeerInterface)
		p->guid=rakPeerInterface->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS);
#if _RAKNET_SUPPORT_PacketizedTCP==1 && _RAKNET_SUPPORT_TCPInterface==1
	else
		p->guid=UNASSIGNED_RAKNET_GUID;
#endif
	p->systemAddress=UNASSIGNED_SYSTEM_ADDRESS;
	p->systemAddress.systemIndex=(SystemIndex)-1;
	memcpy(p->data,out.GetData(),out.GetNumberOfBytesUsed());
	PushBackPacketUnified(p,false);
	return;
}
void FileListTransfer::Send(FileList *fileList, RakPeerInterface *rakPeer, SystemAddress recipient, unsigned short setID, PacketPriority priority, char orderingChannel, bool compressData, IncrementalReadInterface *_incrementalReadInterface, unsigned int _chunkSize)
{
	(void) compressData;

	if (callback)
		fileList->SetCallback(callback);

	unsigned int i, totalLength;
	RakNet::BitStream outBitstream;
	bool sendReference;
	char *dataBlocks[2];
	int lengths[2];
	totalLength=0;
	for (i=0; i < fileList->fileList.Size(); i++)
	{
		const FileListNode &fileListNode = fileList->fileList[i];
		totalLength+=fileListNode.fileLengthBytes;
	}

	// 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);
	
		for (i=0; i < fileList->fileList.Size(); i++)
		{
			outBitstream.Reset();
			sendReference = fileList->fileList[i].isAReference && _incrementalReadInterface!=0;
			if (sendReference)
			{
				StoreForPush(fileList->fileList[i].context, setID, fileList->fileList[i].filename, fileList->fileList[i].fullPathToFile, i, fileList->fileList[i].fileLengthBytes, fileList->fileList[i].dataLengthBytes, recipient, priority, orderingChannel, _incrementalReadInterface, _chunkSize);
				continue;
			}

			outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_FILE);
			
			outBitstream.Write(fileList->fileList[i].context);
			outBitstream.Write(setID);
			stringCompressor->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;
			if (rakPeer)
				rakPeer->SendList(dataBlocks,lengths,2,priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
			else
				SendListUnified(dataBlocks,lengths,2,priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
		}
	}
	else
	{
		if (rakPeer)
			rakPeer->Send(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
		else
			SendUnified(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
	}
}
void FileListTransfer::Send(FileList *fileList, RakPeerInterface *rakPeer, SystemAddress recipient, unsigned short setID, PacketPriority priority, char orderingChannel, bool compressData, IncrementalReadInterface *_incrementalReadInterface, unsigned int _chunkSize)
{
	(void) compressData;

	if (callback)
		fileList->SetCallback(callback);

	unsigned int i, totalLength;
	RakNet::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.fileLengthBytes;
	}

	// 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 = RakNet::OP_NEW<FileToPush>(__FILE__,__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__,__LINE__);
			}
			else
			{
				outBitstream.Reset();
				outBitstream.Write((MessageID)ID_FILE_LIST_TRANSFER_FILE);

				outBitstream.Write(fileList->fileList[i].context);
				outBitstream.Write(setID);
				stringCompressor->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=0;
			filesToPushAllSameAddressMutex.Lock();
			for (unsigned int i=0; i < filesToPushAllSameAddress.Size(); i++)
			{
				if (filesToPushAllSameAddress[i]->systemAddress==recipient)
				{
					ftpr=filesToPushAllSameAddress[i];
					break;
				}
			}
			if (ftpr==0)
			{
				ftpr = RakNet::OP_NEW<FileToPushRecipient>(__FILE__,__LINE__);
				ftpr->systemAddress=recipient;
				filesToPushAllSameAddress.Push(ftpr, __FILE__,__LINE__);
			}
			while (filesToPush.IsEmpty()==false)
			{
				ftpr->filesToPush.Push(filesToPush.Pop(), __FILE__,__LINE__);
			}
			filesToPushAllSameAddressMutex.Unlock();
			SendIRIToAddress(recipient);
			return;
		}
	}
	else
	{
		if (rakPeer)
			rakPeer->Send(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
		else
			SendUnified(&outBitstream, priority, RELIABLE_ORDERED, orderingChannel, recipient, false);
	}
}
void FileListTransfer::SendIRIToAddress(SystemAddress systemAddress)
{
	// 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;
	RakNet::BitStream outBitstream;

	filesToPushAllSameAddressMutex.Lock();
	for (unsigned int ftpIndex=0; ftpIndex < filesToPushAllSameAddress.Size(); ftpIndex++)
	{
		FileToPushRecipient *ftpr = filesToPushAllSameAddress[ftpIndex];
		if (ftpr->systemAddress==systemAddress)
		{
			FileToPush *ftp = ftpr->filesToPush.Peek();

			// Read and send chunk. If done, delete at this index
			void *buff = rakMalloc_Ex(ftp->chunkSize, __FILE__, __LINE__);
			if (buff==0)
			{
				filesToPushAllSameAddressMutex.Unlock();
				notifyOutOfMemory(__FILE__, __LINE__);
				return;
			}

			bytesRead=ftp->incrementalReadInterface->GetFilePart(ftp->fileListNode.fullPathToFile, ftp->currentOffset, ftp->chunkSize, buff, ftp->fileListNode.context);
			bool done = bytesRead!=ftp->chunkSize;
			while (done && ftp->currentOffset==0 && ftpr->filesToPush.Size()>=2 && smallFileTotalSize<ftp->chunkSize)
			{
				// 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.Write(ftp->setID);
				stringCompressor->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;
				SendListUnified(dataBlocks,lengths,2,ftp->packetPriority, RELIABLE_ORDERED, ftp->orderingChannel, systemAddress, false);

				RakNet::OP_DELETE(ftp,__FILE__,__LINE__);
				ftpr->filesToPush.Pop();
				smallFileTotalSize+=bytesRead;
				done = bytesRead!=ftp->chunkSize;
				ftp = ftpr->filesToPush.Peek();
				bytesRead=ftp->incrementalReadInterface->GetFilePart(ftp->fileListNode.fullPathToFile, ftp->currentOffset, ftp->chunkSize, buff, ftp->fileListNode.context);
			}


			outBitstream.Reset();
			outBitstream.Write((MessageID)ID_FILE_LIST_REFERENCE_PUSH);
			outBitstream.Write(ftp->fileListNode.context);
			outBitstream.Write(ftp->setID);
			stringCompressor->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);

			if (callback)
			{
				callback->OnFilePush(ftp->fileListNode.filename, ftp->fileListNode.fileLengthBytes, ftp->currentOffset-bytesRead, bytesRead, done, systemAddress);
			}

			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);
			SendListUnified(dataBlocks,lengths,2,ftp->packetPriority, RELIABLE_ORDERED, ftp->orderingChannel, systemAddress, false);
			if (done)
			{
				// Done
				RakNet::OP_DELETE(ftp,__FILE__,__LINE__);
				ftpr->filesToPush.Pop();
				if (ftpr->filesToPush.Size()==0)
				{
					RakNet::OP_DELETE(ftpr,__FILE__,__LINE__);
					filesToPushAllSameAddress.RemoveAtIndexFast(ftpIndex);
				}
			}
			rakFree_Ex(buff, __FILE__, __LINE__ );
			break;
		}
	}
	filesToPushAllSameAddressMutex.Unlock();
}
Esempio n. 9
0
bool RPC3::SendCallOrSignal(RakString uniqueIdentifier, char parameterCount, RakNet::BitStream *serializedParameters, bool isCall)
{	
	SystemAddress systemAddr;
//	unsigned int outerIndex;
//	unsigned int innerIndex;

	if (uniqueIdentifier.IsEmpty())
		return false;

	RakNet::BitStream bs;
	if (outgoingTimestamp!=0)
	{
		bs.Write((MessageID)ID_TIMESTAMP);
		bs.Write(outgoingTimestamp);
	}
	bs.Write((MessageID)ID_AUTO_RPC_CALL);
	bs.Write(parameterCount);
	if (outgoingNetworkID!=UNASSIGNED_NETWORK_ID && isCall)
	{
		bs.Write(true);
		bs.Write(outgoingNetworkID);
	}
	else
	{
		bs.Write(false);
	}
	bs.Write(isCall);
	// This is so the call SetWriteOffset works
	bs.AlignWriteToByteBoundary();
	BitSize_t writeOffset = bs.GetWriteOffset();
	if (outgoingBroadcast)
	{
		unsigned systemIndex;
		for (systemIndex=0; systemIndex < rakPeerInterface->GetMaximumNumberOfPeers(); systemIndex++)
		{
			systemAddr=rakPeerInterface->GetSystemAddressFromIndex(systemIndex);
			if (systemAddr!=UNASSIGNED_SYSTEM_ADDRESS && systemAddr!=outgoingSystemAddress)
			{
// 				if (GetRemoteFunctionIndex(systemAddr, uniqueIdentifier, &outerIndex, &innerIndex, isCall))
// 				{
// 					// Write a number to identify the function if possible, for faster lookup and less bandwidth
// 					bs.Write(true);
// 					if (isCall)
// 						bs.WriteCompressed(remoteFunctions[outerIndex]->operator [](innerIndex).functionIndex);
// 					else
// 						bs.WriteCompressed(remoteSlots[outerIndex]->operator [](innerIndex).functionIndex);
// 				}
// 				else
// 				{
// 					bs.Write(false);
					stringCompressor->EncodeString(uniqueIdentifier, 512, &bs, 0);
//				}

				bs.WriteCompressed(serializedParameters->GetNumberOfBitsUsed());
				bs.WriteAlignedBytes((const unsigned char*) serializedParameters->GetData(), serializedParameters->GetNumberOfBytesUsed());
				SendUnified(&bs, outgoingPriority, outgoingReliability, outgoingOrderingChannel, systemAddr, false);

				// Start writing again after ID_AUTO_RPC_CALL
				bs.SetWriteOffset(writeOffset);
			}
		}
	}
	else
	{
		systemAddr = outgoingSystemAddress;
		if (systemAddr!=UNASSIGNED_SYSTEM_ADDRESS)
		{
// 			if (GetRemoteFunctionIndex(systemAddr, uniqueIdentifier, &outerIndex, &innerIndex, isCall))
// 			{
// 				// Write a number to identify the function if possible, for faster lookup and less bandwidth
// 				bs.Write(true);
// 				if (isCall)
// 					bs.WriteCompressed(remoteFunctions[outerIndex]->operator [](innerIndex).functionIndex);
// 				else
// 					bs.WriteCompressed(remoteSlots[outerIndex]->operator [](innerIndex).functionIndex);
// 			}
// 			else
// 			{
// 				bs.Write(false);
				stringCompressor->EncodeString(uniqueIdentifier, 512, &bs, 0);
//			}

			bs.WriteCompressed(serializedParameters->GetNumberOfBitsUsed());
			bs.WriteAlignedBytes((const unsigned char*) serializedParameters->GetData(), serializedParameters->GetNumberOfBytesUsed());
			SendUnified(&bs, outgoingPriority, outgoingReliability, outgoingOrderingChannel, systemAddr, false);
		}
		else
			return false;
	}
	return true;
}
Esempio n. 10
0
PluginReceiveResult Router::OnReceive(Packet *packet)
{
	if (packet->data[0]==ID_ROUTE_AND_MULTICAST ||
		(packet->length>5 && packet->data[0]==ID_TIMESTAMP && packet->data[5]==ID_ROUTE_AND_MULTICAST))
	{
#ifdef _DO_PRINTF
		RAKNET_DEBUG_PRINTF("%i got routed message from %i\n", peer->GetExternalID(packet->systemAddress).port, packet->systemAddress.port);
#endif
		RakNetTime timestamp;
		PacketPriority priority;
		PacketReliability reliability;
		unsigned char orderingChannel;
		SystemAddress originalSender;
		RakNet::BitStream out;
		BitSize_t outStartingOffset;
		unsigned int payloadBitLength;
		unsigned payloadWriteByteOffset;
		RakNet::BitStream incomingBitstream(packet->data, packet->length, false);
		incomingBitstream.IgnoreBits(8);
		
		if (packet->data[0]==ID_TIMESTAMP)
		{
			incomingBitstream.Read(timestamp);
			out.Write((MessageID)ID_TIMESTAMP);
			out.Write(timestamp);
			incomingBitstream.IgnoreBits(8);
		}

		// Read the send parameters
		unsigned char c;
		incomingBitstream.ReadCompressed(c);
		priority=(PacketPriority)c;
		incomingBitstream.ReadCompressed(c);
		reliability=(PacketReliability)c;
		incomingBitstream.ReadCompressed(orderingChannel);
		incomingBitstream.Read(payloadBitLength);
		
		out.Write((MessageID)ID_ROUTE_AND_MULTICAST);
		out.WriteCompressed((unsigned char)priority);
		out.WriteCompressed((unsigned char)reliability);
		out.WriteCompressed((unsigned char)orderingChannel);
		out.Write(payloadBitLength);
		out.AlignWriteToByteBoundary();
		incomingBitstream.AlignReadToByteBoundary();
		payloadWriteByteOffset=(unsigned int) BITS_TO_BYTES(out.GetWriteOffset());
		out.Write(&incomingBitstream, payloadBitLength); // This write also does a read on incomingBitStream

		if (restrictByType)
		{
			RakNet::BitStream t(out.GetData()+payloadWriteByteOffset, sizeof(unsigned char), false);
			MessageID messageID;
			t.Read(messageID);
			if (allowedTypes.HasData(messageID)==false)
				return RR_STOP_PROCESSING_AND_DEALLOCATE; // Don't route restricted types
		}

		incomingBitstream.Read(originalSender);
		out.Write(originalSender);
		outStartingOffset=out.GetWriteOffset();

		// Deserialize the root
		bool hasData=false;
		SystemAddress recipient;
		unsigned short numberOfChildren;
		incomingBitstream.Read(hasData);
		incomingBitstream.Read(recipient); // This should be our own address
		if (incomingBitstream.ReadCompressed(numberOfChildren)==false)
		{
#ifdef _DEBUG
			RakAssert(0);
#endif
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		}

		unsigned childIndex;
		bool childHasData=false;
		SystemAddress childRecipient;
		unsigned short childNumberOfChildren;
		SystemAddress immediateRecipient;
		immediateRecipient=UNASSIGNED_SYSTEM_ADDRESS;
		int pendingNodeCount=0;

		for (childIndex=0; childIndex < numberOfChildren; childIndex++)
		{
			while (pendingNodeCount!=-1)
			{
				// Copy out the serialized subtree for this child
				incomingBitstream.Read(childHasData);
				incomingBitstream.Read(childRecipient);
				if (!incomingBitstream.ReadCompressed(childNumberOfChildren))
					return RR_STOP_PROCESSING_AND_DEALLOCATE;
				if (immediateRecipient==UNASSIGNED_SYSTEM_ADDRESS)
				{
					immediateRecipient=childRecipient;
				}

				pendingNodeCount+=childNumberOfChildren-1;

				out.Write(childHasData);
				out.Write(childRecipient);
				out.WriteCompressed(childNumberOfChildren);
			}

#ifdef _DO_PRINTF
			RAKNET_DEBUG_PRINTF("%i routing to %i\n", peer->GetExternalID(packet->systemAddress).port, immediateRecipient.port);
#endif

			// Send what we got so far
			SendUnified(&out, priority, reliability, orderingChannel, immediateRecipient, false);

			// Restart writing the per recipient data
			out.SetWriteOffset(outStartingOffset);

			// Reread the top level node
			immediateRecipient=UNASSIGNED_SYSTEM_ADDRESS;

			pendingNodeCount=0;

		}

		// Write the user payload to the packet struct if this is a destination and change the sender and return true
		if (hasData)
		{
#ifdef _DO_PRINTF
			RAKNET_DEBUG_PRINTF("%i returning payload to user\n", peer->GetExternalID(packet->systemAddress).port);
#endif

			if (packet->data[0]==ID_TIMESTAMP )
			{
				memcpy( packet->data + sizeof(RakNetTime)+sizeof(unsigned char), out.GetData()+payloadWriteByteOffset, BITS_TO_BYTES(payloadBitLength) );
				packet->bitSize=BYTES_TO_BITS(sizeof(RakNetTime)+sizeof(unsigned char))+payloadBitLength;
			}
			else
			{
				memcpy( packet->data, out.GetData()+payloadWriteByteOffset, BITS_TO_BYTES(payloadBitLength) );
				packet->bitSize=payloadBitLength;
			}
			packet->length=(unsigned int) BITS_TO_BYTES(packet->bitSize);
			packet->systemAddress.systemIndex=(SystemIndex)-1;
			packet->systemAddress=originalSender;

			return RR_CONTINUE_PROCESSING;
		}

		// Absorb
		return RR_STOP_PROCESSING_AND_DEALLOCATE;
	}

	return RR_CONTINUE_PROCESSING;
}
Esempio n. 11
0
int SendIRIToAddressCB(FileListTransfer::ThreadData threadData, bool *returnOutput, void* perThreadData)
{
	(void) perThreadData;

	FileListTransfer *fileListTransfer = threadData.fileListTransfer;
	SystemAddress systemAddress = threadData.systemAddress;
	*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;
	RakNet::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)
		{
			FileListTransfer::FileToPush *ftp = ftpr->filesToPush.Peek();

			// Read and send chunk. If done, delete at this index
			void *buff = rakMalloc_Ex(ftp->chunkSize, _FILE_AND_LINE_);
			if (buff==0)
			{
				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 && ftpr->filesToPush.Size()>=2 && smallFileTotalSize<ftp->chunkSize)
			{
				// 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(ftp->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;
				RakNet::OP_DELETE(ftp,_FILE_AND_LINE_);
				ftpr->filesToPush.Pop();
				smallFileTotalSize+=bytesRead;
				//done = bytesRead!=ftp->chunkSize;
				ftp = ftpr->filesToPush.Peek();

				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(ftp->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, ftp->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);
			fileListTransfer->SendListUnified(dataBlocks,lengths,2,ftp->packetPriority, RELIABLE_ORDERED, ftp->orderingChannel, systemAddress, false);

			// Mutex state: FileToPushRecipient (ftpr) has AddRef. fileToPushRecipientListMutex not locked.
			if (done)
			{
				// Done
				unsigned short setId = ftp->setID;
				RakNet::OP_DELETE(ftp,_FILE_AND_LINE_);
				ftpr->filesToPush.Pop();

				if (ftpr->filesToPush.Size()==0)
				{
					for (unsigned int flpcIndex=0; flpcIndex < fileListTransfer->fileListProgressCallbacks.Size(); flpcIndex++)
						fileListTransfer->fileListProgressCallbacks[flpcIndex]->OnFilePushesComplete(systemAddress, setId);

					// Remove ftpr from fileToPushRecipientList
					fileListTransfer->RemoveFromList(ftpr);
				}
			}

			// ftpr out of scope
			ftpr->Deref();

			rakFree_Ex(buff, _FILE_AND_LINE_ );
			return 0;
		}
		else
		{
			ftpr->Deref();
			fileListTransfer->fileToPushRecipientListMutex.Lock();
		}
	}

	fileListTransfer->fileToPushRecipientListMutex.Unlock();

	return 0;
}
Esempio n. 12
0
void AutoRPC::OnRPCUnknownRemoteIndex(SystemAddress systemAddress, unsigned char *data, unsigned int lengthInBytes, RakNetTime timestamp)
{
	char inputStack[ARPC_MAX_STACK_SIZE];
	NetworkID networkId;
	bool hasNetworkId=false;
	unsigned int functionIndex;
	unsigned int bytesOnStack;
	int numberOfBitsUsed;
	char parameterCount;
	bool hasParameterCount=false;

	RakNet::BitStream extraData;
	RakNet::BitStream bs(data,lengthInBytes,false);
	bs.Read(hasParameterCount);
	if (hasParameterCount)
		bs.Read(parameterCount);
	bs.ReadCompressed(functionIndex);
	bs.ReadCompressed(numberOfBitsUsed);
	extraData.AddBitsAndReallocate(numberOfBitsUsed);
	bs.ReadBits(extraData.GetData(), numberOfBitsUsed, false);
	extraData.SetWriteOffset(numberOfBitsUsed);
	bs.Read(hasNetworkId);
	if (hasNetworkId)
		bs.Read(networkId);
	bs.ReadCompressed(bytesOnStack);
	bs.ReadAlignedBytes((unsigned char*) inputStack, bytesOnStack);

	unsigned outerIndex;
	if (remoteFunctions.Has(systemAddress))
	{
		outerIndex = remoteFunctions.GetIndexAtKey(systemAddress);
		DataStructures::OrderedList<RPCIdentifier, RemoteRPCFunction, AutoRPC::RemoteRPCFunctionComp> *theList = remoteFunctions[outerIndex];
		unsigned i;
		for (i=0; i < theList->Size(); i++)
		{
			if (theList->operator [](i).functionIndex==functionIndex)
			{
				RakNet::BitStream out;
				// Recover by resending the RPC with the function identifier string this time
				if (timestamp!=0)
				{
					out.Write((MessageID)ID_TIMESTAMP);
					out.Write(timestamp);
				}
				out.Write((MessageID)ID_AUTO_RPC_CALL);
				if (parameterCount>=0)
				{
					out.Write(true);
					out.Write(parameterCount);
				}
				else
				{
					out.Write(false);
				}				
				out.WriteCompressed(numberOfBitsUsed);
				out.Write(&extraData);
				out.Write(hasNetworkId);
				if (hasNetworkId)
					out.Write(networkId);
				out.AlignWriteToByteBoundary();
				out.Write(false);
				stringCompressor->EncodeString(theList->operator [](i).identifier.uniqueIdentifier, 512, &out, 0);
				out.WriteCompressed(bytesOnStack);
				out.WriteAlignedBytes((const unsigned char*) inputStack, bytesOnStack);
				SendUnified(&out, outgoingPriority, outgoingReliability, outgoingOrderingChannel, systemAddress, false);
				return;
			}
		}
	}

	// Failed to recover, inform the user
	Packet *p = rakPeerInterface->AllocatePacket(sizeof(MessageID)+sizeof(unsigned char));
	RakNet::BitStream bs2(p->data, sizeof(MessageID)+sizeof(unsigned char), false);
	bs2.SetWriteOffset(0);
	bs2.Write((MessageID)ID_RPC_REMOTE_ERROR);
	bs2.Write((unsigned char)RPC_ERROR_FUNCTION_NO_LONGER_REGISTERED);
	stringCompressor->EncodeString("",256,&bs,0);
	p->systemAddress=systemAddress;
	rakPeerInterface->PushBackPacket(p, false);

}
Esempio n. 13
0
bool AutoRPC::SendCall(const char *uniqueIdentifier, const char *stack, unsigned int bytesOnStack, char parameterCount)
{
	SystemAddress systemAddr;
	RPCIdentifier identifier;
	unsigned int outerIndex;
	unsigned int innerIndex;

	if (uniqueIdentifier==0)
		return false;

	identifier.uniqueIdentifier=(char*) uniqueIdentifier;
	identifier.isObjectMember=(outgoingNetworkID!=UNASSIGNED_NETWORK_ID);

	RakNet::BitStream bs;
	if (outgoingTimestamp!=0)
	{
		bs.Write((MessageID)ID_TIMESTAMP);
		bs.Write(outgoingTimestamp);
	}
	bs.Write((MessageID)ID_AUTO_RPC_CALL);
	if (parameterCount>=0)
	{
		bs.Write(true);
		bs.Write(parameterCount);
	}
	else
	{
		bs.Write(false);
	}
	bs.WriteCompressed(outgoingExtraData.GetNumberOfBitsUsed());
	bs.Write(&outgoingExtraData);
	if (outgoingNetworkID!=UNASSIGNED_NETWORK_ID)
	{
		bs.Write(true);
		bs.Write(outgoingNetworkID);
	}
	else
	{
		bs.Write(false);
	}
	// This is so the call SetWriteOffset works
	bs.AlignWriteToByteBoundary();
	BitSize_t writeOffset = bs.GetWriteOffset();
	SystemAddress outgoingSystemAddress;
	if (outgoingSystemIdentifier.rakNetGuid!=UNASSIGNED_RAKNET_GUID)
		outgoingSystemAddress = rakPeerInterface->GetSystemAddressFromGuid(outgoingSystemIdentifier.rakNetGuid);
	else
		outgoingSystemAddress = outgoingSystemIdentifier.systemAddress;
	if (outgoingBroadcast)
	{
		unsigned systemIndex;
		for (systemIndex=0; systemIndex < rakPeerInterface->GetMaximumNumberOfPeers(); systemIndex++)
		{
			systemAddr=rakPeerInterface->GetSystemAddressFromIndex(systemIndex);
			if (systemAddr!=UNASSIGNED_SYSTEM_ADDRESS && systemAddr!=outgoingSystemAddress)
			{
				if (GetRemoteFunctionIndex(systemAddr, identifier, &outerIndex, &innerIndex))
				{
					// Write a number to identify the function if possible, for faster lookup and less bandwidth
					bs.Write(true);
					bs.WriteCompressed(remoteFunctions[outerIndex]->operator [](innerIndex).functionIndex);
				}
				else
				{
					bs.Write(false);
					stringCompressor->EncodeString(uniqueIdentifier, 512, &bs, 0);
				}

				bs.WriteCompressed(bytesOnStack);
				bs.WriteAlignedBytes((const unsigned char*) stack, bytesOnStack);
				SendUnified(&bs, outgoingPriority, outgoingReliability, outgoingOrderingChannel, systemAddr, false);

				// Start writing again after ID_AUTO_RPC_CALL
				bs.SetWriteOffset(writeOffset);
			}
		}
	}
	else
	{
		systemAddr = outgoingSystemAddress;
		if (systemAddr!=UNASSIGNED_SYSTEM_ADDRESS)
		{
			if (GetRemoteFunctionIndex(systemAddr, identifier, &outerIndex, &innerIndex))
			{
				// Write a number to identify the function if possible, for faster lookup and less bandwidth
				bs.Write(true);
				bs.WriteCompressed(remoteFunctions[outerIndex]->operator [](innerIndex).functionIndex);
			}
			else
			{
				bs.Write(false);
				stringCompressor->EncodeString(uniqueIdentifier, 512, &bs, 0);
			}

			bs.WriteCompressed(bytesOnStack);
			bs.WriteAlignedBytes((const unsigned char*) stack, bytesOnStack);
			SendUnified(&bs, outgoingPriority, outgoingReliability, outgoingOrderingChannel, systemAddr, false);
		}
		else
			return false;
	}
	return true;
}
Esempio n. 14
0
void FileListTransfer::Send(FileList *fileList, RakNet::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;
	RakNet::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 = RakNet::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 (unsigned int 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 = RakNet::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);
	}
}