void Server::UpdatePingResponse()
		{
			ECS::Entity* serverInfoEntity = m_world->GetTagManager()->GetEntityByTag("ServerInformation");
			Network::ServerInformationComponent* serverInfo = m_world->GetEntityManager()->GetComponent<Network::ServerInformationComponent>(serverInfoEntity);

			RakNet::BitStream bs;
			serverInfo->Information.Serialize(true, &bs);

			const unsigned char* data = bs.GetData();
			unsigned int size = bs.GetNumberOfBytesUsed();

			m_peer->SetOfflinePingResponse((const char*)bs.GetData(), bs.GetNumberOfBytesUsed());
		}
void StringCompressor::EncodeString( const char *input, int maxCharsToWrite, RakNet::BitStream *output, int languageID )
{
	HuffmanEncodingTree *huffmanEncodingTree;
	if (huffmanEncodingTrees.Has(languageID)==false)
		return;
	huffmanEncodingTree=huffmanEncodingTrees.Get(languageID);

	if ( input == 0 )
	{
		output->WriteCompressed( (unsigned short) 0 );
		return;
	}

	RakNet::BitStream encodedBitStream;

	unsigned short stringBitLength;

	int charsToWrite;

	if ( maxCharsToWrite<=0 || ( int ) strlen( input ) < maxCharsToWrite )
		charsToWrite = ( int ) strlen( input );
	else
		charsToWrite = maxCharsToWrite - 1;

	huffmanEncodingTree->EncodeArray( ( unsigned char* ) input, charsToWrite, &encodedBitStream );

	stringBitLength = ( unsigned short ) encodedBitStream.GetNumberOfBitsUsed();

	output->WriteCompressed( stringBitLength );

	output->WriteBits( encodedBitStream.GetData(), stringBitLength );
}
void EncodeClassName( char *name, char *identifier )
{
    RakNet::BitStream bitStream;
    int index = 0;
    unsigned char byte;

    while ( index < MAXIMUM_CLASS_IDENTIFIER_LENGTH - 1 )
    {
        if ( name[ index ] == 0 )
            break;

        // This should generate a unique identifier for any realistic class name that is 5/8th the length of the actual name and weakly encrypts and compresses it
        if ( name[ index ] >= 'a' && name[ index ] <= 'z' )
            byte = name[ index ] - 'a';
        else if ( name[ index ] >= 'A' && name[ index ] <= 'Z' )
            byte = name[ index ] - 'A';
        else if ( name[ index ] >= '0' && name[ index ] <= '9' )
            byte = name[ index ] - '0';
        else
            byte = name[ index ] << 3;

        bitStream.WriteBits( ( unsigned char* ) & byte, 5 );

        index++;
    }

#ifdef _DEBUG
    memset( identifier, 0, MAXIMUM_CLASS_IDENTIFIER_LENGTH );

#endif

    identifier[ 0 ] = ( char ) ( bitStream.GetNumberOfBytesUsed() );

    memcpy( identifier + 1, bitStream.GetData(), bitStream.GetNumberOfBytesUsed() );
}
Exemple #4
0
void UploadInstanceToCloud(RakNet::CloudClient *cloudClient, RakNet::RakNetGUID serverGuid)
{
    RakNet::CloudKey cloudKey(CLOUD_CLIENT_PRIMARY_KEY,0);
    RakNet::BitStream bs;
    bs.Write("Hello World"); // This could be anything such as player list, game name, etc.
    cloudClient->Post(&cloudKey, bs.GetData(), bs.GetNumberOfBytesUsed(), serverGuid);
}
Exemple #5
0
void Router2::SendOOBFromSpecifiedSocket(OutOfBandIdentifiers oob, SystemAddress sa, SOCKET socket)
{
	RakNet::BitStream bs;
	rakPeerInterface->WriteOutOfBandHeader(&bs);
	bs.Write((unsigned char) oob);
	SocketLayer::SendTo_PC( socket, (const char*) bs.GetData(), bs.GetNumberOfBytesUsed(), sa, __FILE__, __LINE__  );
}
void NatPunchthroughClient::SendOutOfBand(SystemAddress sa, MessageID oobId)
{
	if (sa==UNASSIGNED_SYSTEM_ADDRESS)
		return;
	if (sa.port==0)
		return;


	RakNet::BitStream oob;
	oob.Write(oobId);
	oob.Write(sp.sessionId);
//	RakAssert(sp.sessionId<100);
	if (oobId==ID_NAT_ESTABLISH_BIDIRECTIONAL)
		oob.Write(sa.port);
	char ipAddressString[32];
	sa.ToString(false, ipAddressString);
	rakPeerInterface->SendOutOfBand((const char*) ipAddressString,sa.port,(const char*) oob.GetData(),oob.GetNumberOfBytesUsed());

	if (natPunchthroughDebugInterface)
	{
		sa.ToString(true,ipAddressString);
		char guidString[128];
		sp.targetGuid.ToString(guidString);

		if (oobId==ID_NAT_ESTABLISH_UNIDIRECTIONAL)
			natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Sent OOB ID_NAT_ESTABLISH_UNIDIRECTIONAL to guid %s, system address %s.", guidString, ipAddressString));
		else
			natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Sent OOB ID_NAT_ESTABLISH_BIDIRECTIONAL to guid %s, system address %s.", guidString, ipAddressString));
	}
}
void NatTypeDetectionClient::OnTestPortRestricted(Packet *packet)
{
	RakNet::BitStream bsIn(packet->data,packet->length,false);
	bsIn.IgnoreBytes(sizeof(MessageID));
	RakNet::RakString s3p4StrAddress;
	bsIn.Read(s3p4StrAddress);
	unsigned short s3p4Port;
	bsIn.Read(s3p4Port);

	DataStructures::List<RakNetSocket2* > sockets;
	rakPeerInterface->GetSockets(sockets);
	SystemAddress s3p4Addr = sockets[0]->GetBoundAddress();
	s3p4Addr.FromStringExplicitPort(s3p4StrAddress.C_String(), s3p4Port);

	// Send off the RakNet socket to the specified address, message is unformatted
	// Server does this twice, so don't have to unduly worry about packetloss
	RakNet::BitStream bsOut;
	bsOut.Write((MessageID) NAT_TYPE_PORT_RESTRICTED);
	bsOut.Write(rakPeerInterface->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS));
//	SocketLayer::SendTo_PC( sockets[0], (const char*) bsOut.GetData(), bsOut.GetNumberOfBytesUsed(), s3p4Addr, __FILE__, __LINE__ );

	RNS2_SendParameters bsp;
	bsp.data = (char*) bsOut.GetData();
	bsp.length = bsOut.GetNumberOfBytesUsed();
	bsp.systemAddress=s3p4Addr;
	sockets[0]->Send(&bsp, _FILE_AND_LINE_);

}
void FileListTransfer::PushReference(SystemAddress systemAddress)
{
	// Was previously using GetStatistics to get outgoing buffer size, but TCP with UnifiedSend doesn't have this
	unsigned int i=0;
	unsigned int bytesRead;	
	char *dataBlocks[2];
	int lengths[2];
	RakNet::BitStream outBitstream;
	while (i < filesToPush.Size())
	{
		if (filesToPush[i].systemAddress==systemAddress)
		{
			outBitstream.Reset();
			outBitstream.Write((MessageID)ID_FILE_LIST_REFERENCE_PUSH);
			outBitstream.Write(filesToPush[i].fileListNode.context);
			outBitstream.Write(filesToPush[i].setID);
			stringCompressor->EncodeString(filesToPush[i].fileListNode.filename, 512, &outBitstream);
			outBitstream.WriteCompressed(filesToPush[i].setIndex);
			outBitstream.WriteCompressed(filesToPush[i].fileListNode.dataLengthBytes); // Original length in bytes

			// Read and send chunk. If done, delete at this index
			void *buff = rakMalloc_Ex(filesToPush[i].chunkSize, __FILE__, __LINE__);
			if (buff==0)
			{
				notifyOutOfMemory(__FILE__, __LINE__);
				continue;
			}
			bytesRead=filesToPush[i].incrementalReadInterface->GetFilePart(filesToPush[i].fileListNode.fullPathToFile, filesToPush[i].currentOffset, filesToPush[i].chunkSize, buff, filesToPush[i].fileListNode.context);
			outBitstream.WriteCompressed(filesToPush[i].currentOffset);
			filesToPush[i].currentOffset+=bytesRead;
			outBitstream.WriteCompressed(bytesRead);
			bool done = bytesRead!=filesToPush[i].chunkSize;
			outBitstream.Write(done);

			if (callback)
			{
				callback->OnFilePush(filesToPush[i].fileListNode.filename, filesToPush[i].fileListNode.fileLengthBytes, filesToPush[i].currentOffset-bytesRead, bytesRead, done, filesToPush[i].systemAddress);
			}

			dataBlocks[0]=(char*) outBitstream.GetData();
			lengths[0]=outBitstream.GetNumberOfBytesUsed();
			dataBlocks[1]=(char*) buff;
			lengths[1]=bytesRead;
			//rakPeerInterface->SendList(dataBlocks,lengths,2,filesToPush[i].packetPriority, RELIABLE_ORDERED, filesToPush[i].orderingChannel, filesToPush[i].systemAddress, false);
			SendListUnified(dataBlocks,lengths,2,filesToPush[i].packetPriority, RELIABLE_ORDERED, filesToPush[i].orderingChannel, filesToPush[i].systemAddress, false);
			if (done)
			{
				// Done
				RakNet::OP_DELETE_ARRAY(filesToPush[i].fileListNode.filename, __FILE__, __LINE__);
				filesToPush.RemoveAtIndex(i);
			}
			rakFree_Ex(buff, __FILE__, __LINE__ );
			return;
		}			
		else
			i++;
	}	
}
void CloudServerHelper::OnConnectionCountChange(RakPeerInterface *rakPeer, CloudClient *cloudClient)
{
	RakNet::BitStream bs;
	CloudKey cloudKey(CLOUD_SERVER_CONNECTION_COUNT_PRIMARY_KEY,0);
	unsigned short numberOfSystems;
	rakPeer->GetConnectionList(0, &numberOfSystems);
	bs.Write(numberOfSystems);
	cloudClient->Post(&cloudKey, bs.GetData(), bs.GetNumberOfBytesUsed(), rakPeer->GetMyGUID());
}
void NetworkEngine::updatePingResponse()
{
	RakNet::BitStream data;

	if(isLobby())
	{
		data.Write1();
		unsigned char numPlayers = (unsigned char) peer->NumberOfConnections();
		data.Write(numPlayers);
		std::cout << "Total players: " << (unsigned int) numPlayers << std::endl;
		peer->SetOfflinePingResponse((char *)data.GetData(), data.GetNumberOfBytesUsed());
	} else
	{
		data.Write0();
	}

	peer->SetOfflinePingResponse((char *)data.GetData(), data.GetNumberOfBytesUsed());
}
bool SystemAddressList::Save(const char *filename)
{
	RakNet::BitStream temp;
	Serialize(&temp);
	FILE *fp = fopen(filename, "wb");
	if (fp)
	{
		fwrite(temp.GetData(), (size_t) temp.GetNumberOfBytesUsed(), 1, fp);
		fclose(fp);
		return true;
	}
	return false;
}
void TwoWayAuthentication::PushToUser(MessageID messageId, RakNet::RakString password, RakNet::AddressOrGUID remoteSystem)
{
	RakNet::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);
}
SQLite3ServerPlugin::SQLExecThreadOutput ExecStatementThread(SQLite3ServerPlugin::SQLExecThreadInput threadInput, bool *returnOutput, void* perThreadData)
{
	unsigned int queryId;
	RakNet::RakString dbIdentifier;
	RakNet::RakString inputStatement;
	RakNet::BitStream bsIn((unsigned char*) threadInput.data, threadInput.length, false);
	bsIn.IgnoreBytes(sizeof(MessageID));
	bsIn.Read(queryId);
	bsIn.Read(dbIdentifier);
	bsIn.Read(inputStatement);
	// bool isRequest;
	// bsIn.Read(isRequest);
	bsIn.IgnoreBits(1);

	char *errorMsg;
	RakNet::RakString errorMsgStr;
	SQLite3Table outputTable;					
	sqlite3_exec(threadInput.dbHandle, inputStatement.C_String(), PerRowCallback, &outputTable, &errorMsg);
	if (errorMsg)
	{
		errorMsgStr=errorMsg;
		sqlite3_free(errorMsg);
	}

	RakNet::BitStream bsOut;
	bsOut.Write((MessageID)ID_SQLite3_EXEC);
	bsOut.Write(queryId);
	bsOut.Write(dbIdentifier);
	bsOut.Write(inputStatement);
	bsOut.Write(false);
	bsOut.Write(errorMsgStr);
	outputTable.Serialize(&bsOut);

	// Free input data
	rakFree_Ex(threadInput.data,__FILE__,__LINE__);

	// Copy to output data
	SQLite3ServerPlugin::SQLExecThreadOutput threadOutput;
	threadOutput.data=(char*) rakMalloc_Ex(bsOut.GetNumberOfBytesUsed(),__FILE__,__LINE__);
	memcpy(threadOutput.data,bsOut.GetData(),bsOut.GetNumberOfBytesUsed());
	threadOutput.length=bsOut.GetNumberOfBytesUsed();
	threadOutput.sender=threadInput.sender;	
	// SendUnified(&bsOut, MEDIUM_PRIORITY,RELIABLE_ORDERED,0,packet->systemAddress,false);

	*returnOutput=true;
	return threadOutput;
}
Exemple #14
0
void RakVoice::SetLoopbackMode(bool enabled)
{
	if (enabled)
	{
		Packet p;
		RakNet::BitStream out;
		out.Write((unsigned char)ID_RAKVOICE_OPEN_CHANNEL_REQUEST);
		out.Write((int32_t)sampleRate);
		p.data=out.GetData();
		p.systemAddress=UNASSIGNED_SYSTEM_ADDRESS;
		p.guid=UNASSIGNED_RAKNET_GUID;
		p.length=out.GetNumberOfBytesUsed();
		OpenChannel(&p);
	}
	else
	{
		FreeChannelMemory(UNASSIGNED_RAKNET_GUID);
	}
	loopbackMode=enabled;
}
void NatTypeDetectionClient::OnTestPortRestricted(Packet *packet)
{
	RakNet::BitStream bsIn(packet->data,packet->length,false);
	bsIn.IgnoreBytes(sizeof(MessageID));
	RakNet::RakString s3p4StrAddress;
	bsIn.Read(s3p4StrAddress);
	unsigned short s3p4Port;
	bsIn.Read(s3p4Port);
	SystemAddress s3p4Addr(s3p4StrAddress.C_String(), s3p4Port);

	DataStructures::List<RakNetSmartPtr<RakNetSocket> > sockets;
	rakPeerInterface->GetSockets(sockets);

	// Send off the RakNet socket to the specified address, message is unformatted
	// Server does this twice, so don't have to unduly worry about packetloss
	RakNet::BitStream bsOut;
	bsOut.Write((MessageID) NAT_TYPE_PORT_RESTRICTED);
	bsOut.Write(rakPeerInterface->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS));
	SocketLayer::Instance()->SendTo_PC( sockets[0]->s, (const char*) bsOut.GetData(), bsOut.GetNumberOfBytesUsed(), s3p4Addr.binaryAddress, s3p4Addr.port);
}
void NatPunchthroughClient::SendOutOfBand(SystemAddress sa, MessageID oobId)
{
	if (sa==UNASSIGNED_SYSTEM_ADDRESS)
		return;
	if (sa.GetPort()==0)
		return;

	RakNet::BitStream oob;
	oob.Write(oobId);
	oob.Write(sp.sessionId);
//	RakAssert(sp.sessionId<100);
	if (oobId==ID_NAT_ESTABLISH_BIDIRECTIONAL)
		oob.Write(sa.GetPort());
	char ipAddressString[32];
	sa.ToString(false, ipAddressString);
	rakPeerInterface->SendOutOfBand((const char*) ipAddressString,sa.GetPort(),(const char*) oob.GetData(),oob.GetNumberOfBytesUsed());

	if (natPunchthroughDebugInterface)
	{
		sa.ToString(true,ipAddressString);
		char guidString[128];
		sp.targetGuid.ToString(guidString);

		// server - diff = my time
		// server = myTime + diff
		RakNet::Time clockDifferential = rakPeerInterface->GetClockDifferential(sp.facilitator);
		RakNet::Time serverTime = RakNet::GetTime() + clockDifferential;

		if (oobId==ID_NAT_ESTABLISH_UNIDIRECTIONAL)
			natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("%I64d: %s: OOB ID_NAT_ESTABLISH_UNIDIRECTIONAL to guid %s, system address %s.\n", serverTime, TestModeToString(sp.testMode), guidString, ipAddressString));
		else
			natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("%I64d: %s: OOB ID_NAT_ESTABLISH_BIDIRECTIONAL to guid %s, system address %s.\n", serverTime, TestModeToString(sp.testMode), guidString, ipAddressString));
	}
}
Exemple #17
0
const char *EmailSender::Send(const char *hostAddress, unsigned short hostPort, const char *sender, const char *recipient, const char *senderName, const char *recipientName, const char *subject, const char *body, FileList *attachedFiles, bool doPrintf, const char *password)
{
	RakNet::Packet *packet;
	char query[1024];
	TCPInterface tcpInterface;
	SystemAddress emailServer;
	if (tcpInterface.Start(0, 0)==false)
		return "Unknown error starting TCP";
	emailServer=tcpInterface.Connect(hostAddress, hostPort,true);
	if (emailServer==UNASSIGNED_SYSTEM_ADDRESS)
		return "Failed to connect to host";
#if  OPEN_SSL_CLIENT_SUPPORT==1
	tcpInterface.StartSSLClient(emailServer);
#endif
	RakNet::TimeMS timeoutTime = RakNet::GetTimeMS()+3000;
	packet=0;
	while (RakNet::GetTimeMS() < timeoutTime)
	{
		packet = tcpInterface.Receive();
		if (packet)
		{
			if (doPrintf)
				RAKNET_DEBUG_PRINTF("%s", packet->data);
			break;
		}
		RakSleep(250);
	}

	if (packet==0)
		return "Timeout while waiting for initial data from server.";
	
	tcpInterface.Send("EHLO\r\n", 6, emailServer,false);
	const char *response;
	bool authenticate=false;
#ifdef _MSC_VER
#pragma warning(disable:4127)   // conditional expression is constant
#endif
	while (1)
	{
		response=GetResponse(&tcpInterface, emailServer, doPrintf);

		if (response!=0 && strcmp(response, "AUTHENTICATE")==0)
		{
			authenticate=true;
			break;
		}

		// Something other than continue?
		if (response!=0 && strcmp(response, "CONTINUE")!=0)
			return response;

		// Success?
		if (response==0)
			break;
	}

	if (authenticate)
	{
		sprintf(query, "EHLO %s\r\n", sender);
		tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
		response=GetResponse(&tcpInterface, emailServer, doPrintf);
		if (response!=0)
			return response;
		if (password==0)
			return "Password needed";
		char *outputData = RakNet::OP_NEW_ARRAY<char >((const int) (strlen(sender)+strlen(password)+2)*3, _FILE_AND_LINE_ );
		RakNet::BitStream bs;
		char zero=0;
		bs.Write(&zero,1);
		bs.Write(sender,(const unsigned int)strlen(sender));
		//bs.Write("*****@*****.**",(const unsigned int)strlen("*****@*****.**"));
		bs.Write(&zero,1);
		bs.Write(password,(const unsigned int)strlen(password));
		bs.Write(&zero,1);
		//bs.Write("not.my.real.password",(const unsigned int)strlen("not.my.real.password"));
		Base64Encoding((const char*)bs.GetData(), bs.GetNumberOfBytesUsed(), outputData);
		sprintf(query, "AUTH PLAIN %s", outputData);
		tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
		response=GetResponse(&tcpInterface, emailServer, doPrintf);
		if (response!=0)
			return response;
	}


	if (sender)
		sprintf(query, "MAIL From: <%s>\r\n", sender);
	else
		sprintf(query, "MAIL From: <>\r\n");
	tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
	response=GetResponse(&tcpInterface, emailServer, doPrintf);
	if (response!=0)
		return response;

	if (recipient)
		sprintf(query, "RCPT TO: <%s>\r\n", recipient);
	else
		sprintf(query, "RCPT TO: <>\r\n");
	tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
	response=GetResponse(&tcpInterface, emailServer, doPrintf);
	if (response!=0)
		return response;

	tcpInterface.Send("DATA\r\n", (unsigned int)strlen("DATA\r\n"), emailServer,false);

	// Wait for 354...

	response=GetResponse(&tcpInterface, emailServer, doPrintf);
	if (response!=0)
		return response;

	if (subject)
	{
		sprintf(query, "Subject: %s\r\n", subject);
		tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
	}
	if (senderName)
	{
		sprintf(query, "From: %s\r\n", senderName);
		tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
	}
	if (recipientName)
	{
		sprintf(query, "To: %s\r\n", recipientName);
		tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
	}

	const int boundarySize=60;
	char boundary[boundarySize+1];
	int i,j;
	if (attachedFiles && attachedFiles->fileList.Size())
	{
		rakNetRandom.SeedMT((unsigned int) RakNet::GetTimeMS());
		// Random multipart message boundary
		for (i=0; i < boundarySize; i++)
			boundary[i]=Base64Map()[rakNetRandom.RandomMT()%64];
		boundary[boundarySize]=0;
	}

	sprintf(query, "MIME-version: 1.0\r\n");
	tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);

	if (attachedFiles && attachedFiles->fileList.Size())
	{
		sprintf(query, "Content-type: multipart/mixed; BOUNDARY=\"%s\"\r\n\r\n", boundary);
		tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);

		sprintf(query, "This is a multi-part message in MIME format.\r\n\r\n--%s\r\n", boundary);
		tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
	}
	
	sprintf(query, "Content-Type: text/plain; charset=\"US-ASCII\"\r\n\r\n");
	tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);

	// Write the body of the email, doing some lame shitty shit where I have to make periods at the start of a newline have a second period.
	char *newBody;
	int bodyLength;
	bodyLength=(int)strlen(body);
	newBody = (char*) rakMalloc_Ex( bodyLength*3, _FILE_AND_LINE_ );
	if (bodyLength>0)
		newBody[0]=body[0];
	for (i=1, j=1; i < bodyLength; i++)
	{
		// Transform \n . \r \n into \n . . \r \n
		if (i < bodyLength-2 &&
			body[i-1]=='\n' &&
			body[i+0]=='.' &&
			body[i+1]=='\r' &&
			body[i+2]=='\n')
		{
			newBody[j++]='.';
			newBody[j++]='.';
			newBody[j++]='\r';
			newBody[j++]='\n';
			i+=2;
		}
		// Transform \n . . \r \n into \n . . . \r \n
		// Having to process .. is a bug in the mail server - the spec says ONLY \r\n.\r\n should be transformed
		else if (i <= bodyLength-3 &&
			body[i-1]=='\n' &&
			body[i+0]=='.' &&
			body[i+1]=='.' &&
			body[i+2]=='\r' &&
			body[i+3]=='\n')
		{
			newBody[j++]='.';
			newBody[j++]='.';
			newBody[j++]='.';
			newBody[j++]='\r';
			newBody[j++]='\n';
			i+=3;
		}
		// Transform \n . \n into \n . . \r \n (this is a bug in the mail server - the spec says do not count \n alone but it does)
		else if (i < bodyLength-1 &&
			body[i-1]=='\n' &&
			body[i+0]=='.' &&
			body[i+1]=='\n')
		{
			newBody[j++]='.';
			newBody[j++]='.';
			newBody[j++]='\r';
			newBody[j++]='\n';
			i+=1;
		}
		// Transform \n . . \n into \n . . . \r \n (this is a bug in the mail server - the spec says do not count \n alone but it does)
		// In fact having to process .. is a bug too - because the spec says ONLY \r\n.\r\n should be transformed
		else if (i <= bodyLength-2 &&
			body[i-1]=='\n' &&
			body[i+0]=='.' &&
			body[i+1]=='.' &&
			body[i+2]=='\n')
		{
			newBody[j++]='.';
			newBody[j++]='.';
			newBody[j++]='.';
			newBody[j++]='\r';
			newBody[j++]='\n';
			i+=2;
		}
		else
			newBody[j++]=body[i];
	}
	
	newBody[j++]='\r';
	newBody[j++]='\n';
	tcpInterface.Send(newBody, j, emailServer,false);

	rakFree_Ex(newBody, _FILE_AND_LINE_ );
	int outputOffset;

	// What a pain in the rear.  I have to map the binary to printable characters using 6 bits per character.
	if (attachedFiles && attachedFiles->fileList.Size())
	{
		for (i=0; i < (int) attachedFiles->fileList.Size(); i++)
		{
			// Write boundary
			sprintf(query, "\r\n--%s\r\n", boundary);
			tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);

			sprintf(query, "Content-Type: APPLICATION/Octet-Stream; SizeOnDisk=%i; name=\"%s\"\r\nContent-Transfer-Encoding: BASE64\r\nContent-Description: %s\r\n\r\n", attachedFiles->fileList[i].dataLengthBytes, attachedFiles->fileList[i].filename.C_String(), attachedFiles->fileList[i].filename.C_String());
			tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);

			newBody = (char*) rakMalloc_Ex( (size_t) (attachedFiles->fileList[i].dataLengthBytes*3)/2, _FILE_AND_LINE_ );

			outputOffset=Base64Encoding(attachedFiles->fileList[i].data, (int) attachedFiles->fileList[i].dataLengthBytes, newBody);

			// Send the base64 mapped file.
			tcpInterface.Send(newBody, outputOffset, emailServer,false);
			rakFree_Ex(newBody, _FILE_AND_LINE_ );

		}

		// Write last boundary
		sprintf(query, "\r\n--%s--\r\n", boundary);
		tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
	}


	sprintf(query, "\r\n.\r\n");
	tcpInterface.Send(query, (unsigned int)strlen(query), emailServer,false);
	response=GetResponse(&tcpInterface, emailServer, doPrintf);
	if (response!=0)
		return response;

	tcpInterface.Send("QUIT\r\n", (unsigned int)strlen("QUIT\r\n"), emailServer,false);

	RakSleep(30);
	if (doPrintf)
	{
		packet = tcpInterface.Receive();
		while (packet)
		{
			RAKNET_DEBUG_PRINTF("%s", packet->data);
			packet = tcpInterface.Receive();
		}
	}
	tcpInterface.Stop();
	return 0; // Success
}
void ReplicaObject::writeToPacket(RakNet::BitStream * packet, REPLICA_PACKET_TYPE packetType){
	if (packetType == REPLICA_PACKET_TYPE::REPLICA_CONSTRUCTION_PACKET){
		packet->Write(this->objid);
		packet->Write(this->LOT);

		packet->Write((unsigned char)this->name.size());
		for (unsigned int k = 0; k < this->name.size(); k++){
			packet->Write(this->name.at(k));
		}

		packet->Write(3025001UL);
		//packet->Write(0UL); // time_since_created_on_server (possibly)
		packet->Write(false); // Compressed info... to be added later
		packet->Write(trigger_id); // trigger_id
		packet->Write((bool)(spawnerObjID > 0));
		if (spawnerObjID > 0) { std::cout << "Writing spawnerObjID" << std::endl; packet->Write(spawnerObjID); } // spawnerObjID
		packet->Write((bool)(spawner_node_id >= 0));
		if (spawner_node_id >= 0) { std::cout << "Writing spawner_node_id" << std::endl; packet->Write(spawner_node_id); } // spawnerNodeID
		packet->Write((bool)(floatData >= 0.0));
		if (floatData >= 0.0) { std::cout << "Writing floatData" << std::endl; packet->Write(floatData); } // Unknown floatData
		packet->Write((bool)(objectWorldState >= 0));
		if (objectWorldState >= 0) { std::cout << "Writing objectWorldState" << std::endl; packet->Write(objectWorldState); } // objectWorldState
		packet->Write(this->gmlevel > 0);
		if (this->gmlevel > 0){ std::cout << "Writing gmlevel" << std::endl; packet->Write(this->gmlevel); } // gmlevel
	}
	packet->Write(true);
	packet->Write(false);
	packet->Write(false);

	for (std::vector<ReplicaComponent *>::iterator it = components.begin(); it != components.end(); ++it){
		(*it)->writeToPacket(packet, packetType);
	}

	if (packetType == REPLICA_PACKET_TYPE::REPLICA_CONSTRUCTION_PACKET) {
		/*RakNet::BitStream bs;
		bs.Write((char)0x24);
		bs.Write((bool)true);
		bs.Write((short)280);
		bs.Write(packet);

		std::stringstream ss;
		ss << "ReplicaPacket_" << i << ".bin";
		i++;

		SavePacket(ss.str(), (char*)bs.GetData(), bs.GetNumberOfBytesUsed());*/

		RakNet::BitStream bs;
		bs.Write((char)0x27);
		bs.Write((short)48608);
		bs.Write(false);
		bs.Write(false);
		bs.Write(false);
		bs.Write(false);
		bs.Write(false);
		bs.Write(false);
		bs.Write(false);
		bs.Write(true);
		bs.Write((long)1);
		bs.Write((long long)1152921504606847070);

		std::stringstream ss;
		ss << "ReplicaPacket_" << i << ".bin";
		i++;

		SavePacket(ss.str(), (char*)bs.GetData(), bs.GetNumberOfBytesUsed());
	}
}
Exemple #19
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;
}
// 0=failed, 1=success, 2=ignore
void NatPunchthroughClient::UpdateGroupPunchOnNatResult(SystemAddress facilitator, RakNetGUID targetSystem, SystemAddress targetSystemAddress, int result)
{
	GroupPunchRequest *gpr;
	unsigned long i,j,k;
	i=0;
	while (i < groupPunchRequests.Size())
	{
		gpr = groupPunchRequests[i];
		if (gpr->facilitator==facilitator)
		{
			j=0;
			while (j < gpr->pendingList.Size())
			{
				if (gpr->pendingList[j]==targetSystem)
				{
					if (result==0)
					{
						gpr->failedList.Push(targetSystem, _FILE_AND_LINE_);
					}
					else if (result==1)
					{
						gpr->passedListGuid.Push(targetSystem, _FILE_AND_LINE_);
						gpr->passedListAddress.Push(targetSystemAddress, _FILE_AND_LINE_);
					}
					else
					{
						gpr->ignoredList.Push(targetSystem, _FILE_AND_LINE_);
					}
					gpr->pendingList.RemoveAtIndex(j);
				}
				else
					j++;
			}
		}
		if (gpr->pendingList.Size()==0)
		{
			RakNet::BitStream output;
			if (gpr->failedList.Size()==0)
			{
				output.Write(ID_NAT_GROUP_PUNCH_SUCCEEDED);
			}
			else
			{
				output.Write(ID_NAT_GROUP_PUNCH_FAILED);
			}

			output.WriteCasted<unsigned char>(gpr->passedListGuid.Size());
			for (k=0; k < gpr->passedListGuid.Size(); k++)
			{
				output.Write(gpr->passedListGuid[k]);
				output.Write(gpr->passedListAddress[k]);
			}
			output.WriteCasted<unsigned char>(gpr->ignoredList.Size());
			for (k=0; k < gpr->ignoredList.Size(); k++)
			{
				output.Write(gpr->ignoredList[k]);
			}
			output.WriteCasted<unsigned char>(gpr->failedList.Size());
			for (k=0; k < gpr->failedList.Size(); k++)
			{
				output.Write(gpr->failedList[k]);
			}			

			Packet *p = AllocatePacketUnified(output.GetNumberOfBytesUsed());
			p->systemAddress=gpr->facilitator;
			p->systemAddress.systemIndex=(SystemIndex)-1;
			p->guid=rakPeerInterface->GetGuidFromSystemAddress(gpr->facilitator);
			p->wasGeneratedLocally=true;
			memcpy(p->data, output.GetData(), output.GetNumberOfBytesUsed());
			rakPeerInterface->PushBackPacket(p, true);

			groupPunchRequests.RemoveAtIndex(i);
			RakNet::OP_DELETE(gpr, _FILE_AND_LINE_);
		}
		else
			i++;
	}
}
void CConsole::SendRules(char* queryData, SOCKET socket, const sockaddr_in* to, int tolen)
{
	const char* varName;
	char varValue[1024];

	std::map<std::string, consoleVarStruct*>::iterator itor;

	uint16_t svrRuleCount = 0;
	for (itor = varMap.begin(); itor != varMap.end(); itor++)
		if (itor->second->varFlags & CONSOLE_VARFLAG_RULE)
			svrRuleCount++;

	uint16_t rulesLen = 13 + (svrRuleCount * 62);

#ifndef _USE_BITSTREAMS
	char* dataBuf = new char[rulesLen];
	char* dataPtr = dataBuf;
	
	memcpy(dataBuf, queryData, 11);
	dataBuf += 11;
#else
	RakNet::BitStream rules;
	
	rules.Write((char*)queryData, 11);
	rules.Write(svrRuleCount);
#endif
#ifndef _USE_BITSTREAMS
	memcpy(dataBuf, &svrRuleCount, sizeof(uint16_t));
	dataBuf += sizeof(uint16_t);
#endif

	uint8_t varNameLen;

	for (itor = varMap.begin(); itor != varMap.end(); itor++)
	{
		if (itor->second->varFlags & 4)
		{
			varName = itor->first.c_str();
			switch (itor->second->varType)
			{
				case CONSOLE_VARTYPE_FLOAT:
					sprintf(varValue, "%f", *(float*)itor->second->varValue);
					break;
				case CONSOLE_VARTYPE_INT:
					sprintf(varValue, "%d", *(int*)itor->second->varValue);
					break;
				case CONSOLE_VARTYPE_BOOL:
					sprintf(varValue, "%d", *(bool*)itor->second->varValue);
					break;
				case CONSOLE_VARTYPE_STRING:
					strcpy(varValue, (char*)itor->second->varValue);
					break;
			}

			varNameLen = strlen(varName);
#ifdef _USE_BITSTREAMS
			rules.Write(varNameLen);
			rules.Write(varName, varNameLen);
#else
			memcpy(dataBuf, &varNameLen, sizeof(uint8_t));
			dataBuf += sizeof(uint8_t);
			memcpy(dataBuf, varName, varNameLen);
			dataBuf += varNameLen;
#endif
			varNameLen = strlen(varValue);
#ifdef _USE_BITSTREAMS
			rules.Write(varNameLen);
			rules.Write(varValue, varNameLen);
#else
			memcpy(dataBuf, &varNameLen, sizeof(uint8_t));
			dataBuf += sizeof(uint8_t);

			memcpy(dataBuf, varValue, varNameLen);
			dataBuf += varNameLen;
#endif
		}
	}
#ifdef _USE_BITSTREAMS
	sendto(socket, (char*)rules.GetData(), rules.GetNumberOfBytesUsed(), 0, (sockaddr*)to, tolen);
#else
	sendto(socket, dataPtr, (int)(dataBuf - dataPtr), 0, (sockaddr*)to, tolen);
	delete [] dataPtr;
#endif
}
void WorldLoop(CONNECT_INFO* cfg, Ref< UsersPool > OnlineUsers, Ref< CharactersPool> OnlineCharacters, Ref< CrossThreadQueue< string > > OutputQueue) {
	// Initialize the RakPeerInterface used throughout the entire server
	rakServer = RakNetworkFactory::GetRakPeerInterface();

	// Initialize the PacketFileLogger plugin (for the logs)
	PacketFileLogger* msgFileHandler = NULL;
	if (cfg->logFile) {
		msgFileHandler = new PacketFileLogger();
		rakServer->AttachPlugin(msgFileHandler);
	}

	// Initialize security IF user has enabled it in config.ini
	InitSecurity(rakServer, cfg->useEncryption);

	// Initialize the SocketDescriptor
	SocketDescriptor socketDescriptor(cfg->listenPort, 0);

	// If the startup of the server is successful, print it to the console
	// Otherwise, quit the server (as the char server is REQUIRED for the
	// server to function properly)
	if (rakServer->Startup(8, 30, &socketDescriptor, 1)) {
		stringstream s;
		s << "world started! Listening on: " << cfg->listenPort << "\n";
		OutputQueue->Insert(s.str());
	} else exit(2);

	rakServer->SetNetworkIDManager(&networkIdManager);

	rakServer->AttachPlugin(&replicaManager);
	networkIdManager.SetIsNetworkIDAuthority(true);

	// Attach the ReplicaManager2
	replicaManager.SetAutoSerializeInScope(true);
	replicaManager.SetAutoParticipateNewConnections(true);
	replicaManager.SetAutoConstructToNewParticipants(true);

	// Set max incoming connections to 8
	rakServer->SetMaximumIncomingConnections(8);

	// If msgFileHandler is not NULL, save logs of char server
	if (msgFileHandler != NULL) msgFileHandler->StartLog(".\\logs\\world");

	// Initialize the Packet class for the packets
	Packet* packet;

	// This will be used in the saving of packets below
	int i = 0;

	ZoneId zone = NIMBUS_ISLE;

	// This will be used in the saving of packets below...
	while (!LUNIterminate) {
		RakSleep(30);	// This sleep keeps RakNet responsive
		packet = rakServer->Receive(); // Recieve the packets from the server
		if (packet == NULL) continue; // If packet is NULL, just continue without processing anything

		// This will save all packets recieved from the client if running from DEBUG
		#ifdef DEBUG
			stringstream packetName;
			packetName << ".//Saves//World_Packet" << i << ".bin";

			if (packet->data[3] != 22) {
				SavePacket(packetName.str(), (char*)packet->data, packet->length);
				i++;
			}
		#endif

		// Create and send packets back here according to the one we got
			switch (packet->data[0]) {
			case ID_USER_PACKET_ENUM:
				switch (packet->data[1]) {
				case GENERAL:
					if (packet->data[3] == 0) {	// thats just a formality so far since no other numbers occured for this case
						auto v = OpenPacket(".\\worldTest\\init_aw2.bin");
						ServerSendPacket(rakServer, v, packet->systemAddress);
					}
					break;

				case WORLD:

					switch (packet->data[3]) {
					case CLIENT_VALIDATION:
					{
											  auto usr = OnlineUsers->Find(packet->systemAddress);
											  //this packets contains ZoneId and something else... but what?
											  // it starts whit: 53 05 00 02 00 00 00 00 -- -- (<-ZoneId) ?? ?? ??
											  vector< uchar > v;
											  /*if (usr != NULL && usr->nextcid == 2444680020) { //monkeybrown
												  v = OpenPacket(".\\world\\monkeybrown\\char_aw2.bin");
												  }
												  else if (usr != NULL && usr->nextcid == 1534792735) { //gruntmonkey
												  v = OpenPacket(".\\world\\gruntmonkey\\char_aw2.bin");
												  }
												  else if (usr != NULL && usr->nextcid == 1457240027) { //shafantastic
												  v = OpenPacket(".\\world\\shastafantastic\\char_aw22.bin");
												  }
												  else { //cheekymonkey
												  v = OpenPacket(".\\world\\char_aw2.bin");
												  }*/

											  if (zone == NIMBUS_ISLE)
												  v = OpenPacket(".\\world\\char_aw2.bin");
											  else if (zone == NIMBUS_STATION) {
												  v = OpenPacket(".\\worldTest\\NS\\char_aw2.bin");
											  }
											  else if (zone == LEGO_CLUB) {
												  v = OpenPacket(".\\worldTest\\LC\\char_aw2.bin");
											  }

											  //ReadCompressedLDFData();
#ifdef DEBUG
											  if (v.size() > 0) {
												  RakNet::BitStream bs(CleanPacket(v.data(), v.size()), v.size() - 8, false);
												  ZoneId zid;
												  bs.Read(zid);
												  stringstream s;
												  s << "\nLoading world: " << zid << endl;
												  OutputQueue->Insert(s.str());
											  }
											  else OutputQueue->Insert("\nWorld Error: can't load char_aw2.bin\n");
#endif

											  ServerSendPacket(rakServer, v, packet->systemAddress);

											  if (zone == NIMBUS_ISLE) {
												  //auto character = Character::InitializeCharacter(12241);
												  //character->WriteInitPacket(rakServer, packet->systemAddress);

												  v = OpenPacket(".\\worldTest\\game_msg1.bin");
												  ServerSendPacket(rakServer, v, packet->systemAddress);

												  v = OpenPacket(".\\worldTest\\game_msg2.bin");
												  ServerSendPacket(rakServer, v, packet->systemAddress);
											  }
											  else if (zone == NIMBUS_STATION) {
												  v = OpenPacket(".\\worldTest\\NS\\msg1.bin");
												  ServerSendPacket(rakServer, v, packet->systemAddress);
											  }
											  else if (zone == LEGO_CLUB) {
												  v = OpenPacket(".\\worldTest\\LC\\msg1.bin");
												  ServerSendPacket(rakServer, v, packet->systemAddress);

												  v = OpenPacket(".\\worldTest\\LC\\msg2.bin");
												  ServerSendPacket(rakServer, v, packet->systemAddress);
											  }
					}
						break;

					case CLIENT_GAME_MSG:
					{

#ifdef DEBUG
											vector< uchar > t;
											for (int i = 8; i <= 11; i++) t.push_back(packet->data[i]);
											ulong cid = *(ulong*)t.data();

											cout << "Character wants to do something using packet: " << RawDataToString(packet->data, packet->length) << endl;

											//cout << "\nCharacter id is doing something?: " << cid;
#endif

											if (packet->length >= 18) {
												ushort gameMsg;
												memcpy(&gameMsg, (uchar*)packet->data + 0x10, 2);

												cout << "Game Message ID is: " << gameMsg << endl;

												auto user = OnlineUsers->Find(packet->systemAddress);

												HandleGameMessage(rakServer, packet->systemAddress, gameMsg, (uchar*)packet->data, packet->length, user);

												break;
											}
					}

					case CLIENT_GENERAL_CHAT_MESSAGE:
					{
														auto usr = OnlineUsers->Find(packet->systemAddress);

														vector<uchar> chatMsg;

														/*for (uchar i = 0; i <= packet->length; i++) {
															chatMsg.push_back(packet->data[0x0f + i++]);

															if (packet->data[0x0f + i + 1] == 0) {
															i++;
															break;
															}
															}

															chatMsg.push_back(0);

															string msg(chatMsg.begin(), chatMsg.end());*/

														for (uchar i = 15; i < packet->length; i++) {
															chatMsg.push_back(packet->data[i]);
														}

														string wMsg(chatMsg.begin(), chatMsg.end());

														cout << "User entered: " << wMsg.c_str() << endl;

														RakNet::BitStream bitStream;

														CreatePacketHeader(ID_USER_PACKET_ENUM, 2, 1, &bitStream);

														ulonglong l1 = 0;
														uchar l2 = 0;
														ushort l3 = 0;

														ulonglong senderID = 63515;

														bitStream.Write(l1);
														bitStream.Write(l2);
														bitStream.Write((uchar)(wMsg.length() * 2 + 2));
														bitStream.Write(l2);
														bitStream.Write(l3);

														string x1 = "";

														wstring emptyUser = StringToWString(x1, 66);
														bitStream.Write((char*)emptyUser.data(), sizeof(wchar_t)* emptyUser.size() / 2);
														bitStream.Write(senderID);
														bitStream.Write(l3);
														bitStream.Write((uchar)1);
														bitStream.Write((char*)wMsg.data(), sizeof(char)* wMsg.length());

														rakServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
														SavePacket("msg_response.bin", (char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed());

														/*RakNet::BitStream bitStream2;

														CreatePacketHeader(ID_USER_PACKET_ENUM, 5, 12, &bitStream2);

														ushort u2 = 858;
														ulong u3 = 0;
														ushort u4 = 0;

														bitStream2.Write(u1);
														bitStream2.Write(u2);

														bitStream2.Write(u3);
														bitStream2.Write(u4);
														bitStream2.Write(wMsg.length());
														bitStream2.Write(wMsg);

														rakServer->Send(&bitStream2, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);

														SavePacket("hi_msg.bin", (char*)bitStream2.GetData(), bitStream2.GetNumberOfBytesUsed());*/
					}
						break;

					case CLIENT_LEVEL_LOAD_COMPLETE:
					{
													   // Response: 05, 04
													   // The answer to this is compressed data detailing character data
													   // also since the answer seems to consist of a split packet, does RakNet automatically split the packets if the data is too big? or do we have to do something, if yes what?
													   // byte 08 (2 or 4 bytes long? I guess 4...) seems to define the size of the data we send, no idea what the data itself is though...
													   auto usr = OnlineUsers->Find(packet->systemAddress);

													   // If the user is not equal to null and next character id = below number,
													   // Open the packets of monkeybrown and load him into a world
													   /*if (usr != NULL && usr->nextcid == 2444680020) {
														   cout << "\n Replying to monkeybrown\n";
														   auto v = OpenPacket(".\\world\\monkeybrown\\rocket_1a.bin");
														   ServerSendPacket(rakServer, v, packet->systemAddress);

														   v = OpenPacket(".\\world\\monkeybrown\\rocket_1b.bin");
														   ServerSendPacket(rakServer, v, packet->systemAddress);

														   v = OpenPacket(".\\world\\monkeybrown\\rocket_1c.bin");
														   ServerSendPacket(rakServer, v, packet->systemAddress);

														   v = OpenPacket(".\\world\\monkeybrown\\world_2a.bin");
														   ServerSendPacket(rakServer, v, packet->systemAddress);
														   // test, is this the right thing to do? there's no difference in the process when they are (not) sent so far
														   v = OpenPacket(".\\world\\monkeybrown\\world_2b.bin");   // I assume these two are sent together?
														   ServerSendPacket(rakServer, v, packet->systemAddress);

														   for (int i = 0; i < 42; i++) {  // herpaderp
														   stringstream fl;
														   fl << ".\\world\\monkeybrown\\test\\world_2_" << (i + 1) << ".bin";
														   auto v = OpenPacket(fl.str());
														   ServerSendPacket(rakServer, v, packet->systemAddress);
														   }

														   v = OpenPacket(".\\world\\monkeybrown\\test\\world_2_1.bin");
														   ServerSendPacket(rakServer, v, packet->systemAddress);

														   for (int i = 42; i < 210; i++) {  // herpaderp
														   stringstream fl;
														   fl << ".\\world\\monkeybrown\\test\\world_2_" << (i + 1) << ".bin";
														   auto v = OpenPacket(fl.str());
														   ServerSendPacket(rakServer, v, packet->systemAddress);
														   }
														   } else { // Otherwise, reply to Cheekymonkey and open his packets*/
														cout << "\n Replying to Character\n";

														//auto v = OpenPacket("LEGO Software.bin");

														cout << "Attempting to create new char..." << endl;
														//if (character == 0) {
															//cout << "Creating new char..." << endl;
															//character = new Character(63450);
															//replicaManager.Construct(character, false, UNASSIGNED_SYSTEM_ADDRESS, true);
															//replicaManager.SignalSerializeNeeded(character, UNASSIGNED_SYSTEM_ADDRESS, true);
														//}
													  
														auto v = OpenPacket(".\\world\\world_2a.bin");

														if (v.size() <= 0) {
															cout << "World 2A contains no data!!!!" << endl;
														}

														ServerSendPacket(rakServer, v, packet->systemAddress);
														// test, is this the right thing to do? there's no difference in the process when they are (not) sent so far
														v = OpenPacket(".\\world\\world_2b.bin");	// I assume these two are sent together?
														ServerSendPacket(rakServer, v, packet->systemAddress);

														auto currentChar = OnlineCharacters->Find(packet->systemAddress);
														replicaManager.Construct(currentChar.Get(), false, UNASSIGNED_SYSTEM_ADDRESS, true);

													//replicaManager.Construct(character, false, UNASSIGNED_SYSTEM_ADDRESS, true);

													   if (zone == NIMBUS_ISLE) {
														   for (int i = 1; i < 5; i++) {	// herpaderp
															   stringstream fl;
															   fl << ".\\world\\test\\world_2_" << (i + 1) << ".bin";
															   auto v = OpenPacket(fl.str());
															   ServerSendPacket(rakServer, v, packet->systemAddress);
														   }

														   //auto character = Character::InitializeCharacter(12241);
														   //character->WriteInitPacket(rakServer, packet->systemAddress);
													   }
													   else if (zone == NIMBUS_STATION) {
														   auto v = OpenPacket(".\\worldTest\\NS\\msg1.bin");
														   ServerSendPacket(rakServer, v, packet->systemAddress);

														   for (int i = 1; i < 10; i++) {
															   stringstream fl;
															   fl << ".\\worldTest\\NS\\replica\\ns_replica" << i << ".bin";

															   v = OpenPacket(fl.str());
															   ServerSendPacket(rakServer, v, packet->systemAddress);
														   }

														   for (int j = 1; j < 10; j++) {
															   stringstream fl2;
															   fl2 << ".\\worldTest\\NS\\messages\\ns_message" << j << endl;

															   v = OpenPacket(fl2.str());
															   ServerSendPacket(rakServer, v, packet->systemAddress);
														   }
													   }

													   
													   else if (zone == LEGO_CLUB) {
														   cout << "Loading LEGO CLUB" << endl;

														   for (int i = 47; i < 300; i) {
															   stringstream packetName;

															   packetName << ".\\..\\..\\..\\..\\Downloaded Packets\\GruntMonkey\\Lego Club - 42\\output_data\\" << i << "s.bin";

															   auto v = OpenPacket(packetName.str());

															   if (v.size() > 0) {
																   ServerSendPacket(rakServer, v, packet->systemAddress);
															   }

															   for (int j = 0; j < 20; j) {
																   stringstream packetName2;
																   packetName2 << ".\\..\\..\\..\\..\\Downloaded Packets\\GruntMonkey\\Lego Club - 42\\output_data\\" << i << "s_" << j << ".bin";

																   v = OpenPacket(packetName2.str());

																   if (v.size() > 0) {
																	   ServerSendPacket(rakServer, v, packet->systemAddress);
																   }

																   j++;
															   }

															   i++;
														   }

														   cout << "DONE Loading LEGO CLUB" << endl;
													   }
													   //}

													   /*cout << "Loading Venture Explorer for character..." << endl;

													   auto v = OpenPacket(".\\worldTest\\char\\char_load.bin");
													   ServerSendPacket(rakServer, v, packet->systemAddress);

													   v = OpenPacket(".\\worldTest\\char\\server_status.bin");
													   ServerSendPacket(rakServer, v, packet->systemAddress);

													   for (int i = 1; i <= 50; i++) {
													   stringstream fileName;
													   fileName << ".\\worldTest\\replica\\replica" << i << ".bin";
													   v = OpenPacket(fileName.str());
													   ServerSendPacket(rakServer, v, packet->systemAddress);
													   }*/

													   /*for (int i = 35; i <= 789; i++) {
														   stringstream fileName;

														   fileName << ".\\worldTest\\replicaTest\\" << i << "s.bin";
														   auto v = OpenPacket(fileName.str());

														   if (v.data() > 0) {
														   cout << "Sending file: " << fileName.str() << endl;
														   ServerSendPacket(rakServer, v, packet->systemAddress);
														   }

														   for (int j = 2; j < 12; j++) {
														   stringstream fileNameStr;
														   fileNameStr << ".\\worldTest\\replicaTest\\" << i << "s_" << j << ".bin";

														   v = OpenPacket(fileNameStr.str());

														   if (v.data() > 0) {
														   cout << "Sending file: " << fileNameStr.str() << endl;
														   ServerSendPacket(rakServer, v, packet->systemAddress);
														   }
														   }

														   }*/

					}
						break;

					case CLIENT_MAIL:
					{
										auto usr = OnlineUsers->Find(packet->systemAddress);

										uint mailID;
										memcpy(&mailID, packet->data + 0x08, 4);

										if (mailID == 3) {
											FetchMailData(rakServer, packet->systemAddress, usr);
										}
					}
						break;

					case CLIENT_ROUTE_PACKET:
					{
												uchar remoteConnection;
												uchar packetID;

												memcpy(&remoteConnection, packet->data + 0x0C, 1);
												memcpy(&packetID, packet->data + 0x0E, 1);

												/*if (remoteConnection == 2 && packetID == 10) {
													auto character = OnlineUsers->FindChar(packet->systemAddress);

													character->CreateFriendsList(rakServer, packet->systemAddress, character->charObjectID);
												}*/
					}
						break;

					case CLIENT_STRING_CHECK:
					{
												uchar requestID = packet->data[9];

												cout << "Getting char moderation request with id: " << requestID << endl;

												RakNet::BitStream bitStream;
												CreatePacketHeader(ID_USER_PACKET_ENUM, 5, 59, &bitStream);

												bitStream.Write((uchar)1);
												bitStream.Write((ushort)0);
												bitStream.Write(requestID);

												rakServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
					}
						break;

					case 22: //user moving / update request?
					{
								 auto usr = OnlineUsers->Find(packet->systemAddress);
#ifdef DEBUG
								 //OutputQueue->Insert("Received packet 22: " + RawDataToString(packet->data, packet->length) + "\n");
#endif
					}
						break;

						/*case LUNI_WORLD_CHAT: //user wrote a chat message
						{
						if (packet->length >= 10 && RawDataToString(packet->data + packet->length - 10, 10, true) == "730064006f0077006e00") {//virus used to be here
						}

						// dummy try
						vector< uchar > v(packet->length);
						for (uint i = 0; i < packet->length; i++) v.push_back(packet->data[i]);
						ServerSendPacket(rakServer, v, packet->systemAddress);
						}*/
						break;

						/*case 5:
						{
						#ifdef DEBUG
						vector< uchar > t;
						for (int i = 8; i <= 11; i++) t.push_back(packet->data[i]);
						ulong cid = *(ulong*)t.data();

						cout << "Character wants to do something using packet: " << RawDataToString(packet->data, packet->length) << endl;

						//cout << "\nCharacter id is doing something?: " << cid;
						#endif

						if (packet->data[0x1A] == 123 && packet->data[0x1B] == 33 & packet->data[0x1C] == 22) {
						cout << "Sending char to new world..." << endl;

						zone = NIMBUS_STATION;

						auto v = OpenPacket(".\\worldTest\\init_aw2.bin");
						ServerSendPacket(rakServer, v, packet->systemAddress);
						}
						}
						break;*/

					default:
						stringstream s;
						s << "\nworld received unknow pakcet: " << RawDataToString(packet->data, packet->length) << endl;
						OutputQueue->Insert(s.str());
					}

					break;

				default:
					stringstream s;
					s << "\nworld received unknow pakcet: " << RawDataToString(packet->data, packet->length) << endl;
					OutputQueue->Insert(s.str());
				}
				break;

			case ID_NEW_INCOMING_CONNECTION:
			{
			#ifdef DEBUG
				OutputQueue->Insert("\n World is receiving a new connection...\n");
			#endif

				//replicaManager.AddNewConnection(packet->systemAddress);
				/*Player *newPlayer = new Player;
				newPlayer->SetReplicaManager(&replicaManager);
				newPlayer->systemAddress = packet->systemAddress;
				newPlayer->LOT = 1;
				newPlayer->AddAutoSerializeTimer(100);
				newPlayer->BroadcastConstruction();*/

			}
				break;

			case ID_DISCONNECTION_NOTIFICATION:
			{
				auto usr = OnlineUsers->Find(packet->systemAddress);
				if (OnlineUsers->Remove(packet->systemAddress))
					OutputQueue->Insert("Disconnected " + usr->GetUsername() + "\n");
			}

				//Player::DeletePlayerByAddress(packet->systemAddress);
				delete character;

				break;

			default:
				stringstream s;
				s << "\nworld received unknow pakcet: " << RawDataToString(packet->data, packet->length) << endl;
				OutputQueue->Insert(s.str());
		}

		rakServer->DeallocatePacket(packet);
	}

	stringstream s;
	s << "Quitting world\n";
	OutputQueue->Insert(s.str());

	rakServer->Shutdown(0);
	RakNetworkFactory::DestroyRakPeerInterface(rakServer);
}
void SendCharPacket(RakPeerInterface *rakServer, SystemAddress& systemAddress, Ref<User> usr) {
	RakNet::BitStream bitStream;

	CreatePacketHeader(ID_USER_PACKET_ENUM, 5, 6, &bitStream);
	
	if (usr == NULL) {
		cout << "Usr is null!!! ERROR!" << endl;
	}

	uchar charactersLength = (uchar)usr->userChars;
	uchar frontChar = (uchar)usr->userFrontChar;

	bitStream.Write(charactersLength);
	bitStream.Write(frontChar);

	ostringstream userId;
	userId << usr->GetID();

	cout << userId.str() << endl;

	string userIdStr = userId.str();

	// This loop perhaps is very inefficient, but it makes sure
	// 4 chars are loaded (or, if they don't exist, fill with 0x00)
	for (uint i = 0; i <= charactersLength; i++) {
		CharactersPacket charData = CharactersPacket();

		ostringstream loopSS;
		loopSS << i;
		string loopStr = loopSS.str(); //loopSS.str();

		// Connect to the database and retrieve character info
		auto qr = Database::Query("SELECT * FROM `characters` WHERE `id` = '" + loopStr + "' AND `accountID` = '" + userIdStr + "';");

		// If the number of rows equals 0 from database (character doesn't exist), print it
		if (mysql_num_rows(qr) == 0) {
			cout << "Char " << loopStr <<  " doesn't exist yet.";
		} else {
			// Otherwise, fetch the data in the row
			auto ftc = mysql_fetch_row(qr);

			charData.objectID = (ulonglong)atoi(ftc[2]); // This is the character ID... ftc[1] is the user id
			charData.unknown1 = 0; // Dunno what this is...

			string sCharName = (string)ftc[3]; // This is the character name
			string sUnapprovedName = (string)ftc[4]; // This is the pre-defined (unapproved) name

			/*wstringstream swCharName; // Create a wstringstream for the char name
			swCharName << sCharName.c_str(); // Add the char name to it

			wstringstream swUnapprovedName; // Create a wstringstream for the unapproved name
			swUnapprovedName << sUnapprovedName.c_str(); // Add the unapproved name to it

			wstring wCharName = swCharName.str(); // Create a wstring from the wstringstream
			wstring wUnapprovedName = swUnapprovedName.str(); // Create a wstring from the wstringstream

			wCharName.resize(66);
			wUnapprovedName.resize(66);*/

			wstring wCharName = StringToWString(sCharName, 66);
			wstring wUnapprovedName = StringToWString(sUnapprovedName, 66);
			
			charData.charName = wCharName; // This is the name of the character
			charData.unapprovedName = wUnapprovedName; // This is the unapproved name of the character			
			
			charData.nameRejected = (uchar)atoi(ftc[5]); // This determines whether the user's name is approved
			charData.freeToPlay = (uchar)atoi(ftc[6]); // This determines whether the user if Free to Play
			charData.unknown2 = "";
			charData.shirtColor = (ulong)atoi(ftc[7]); // The shirt color
			charData.shirtStyle = (ulong)atoi(ftc[8]); // Possibly the shirt style... ?
			charData.pantsColor = (ulong)atoi(ftc[9]); // The pants color
			charData.hairStyle = (ulong)atoi(ftc[10]); // Hair style
			charData.hairColor = (ulong)atoi(ftc[11]); // Hair color
			charData.lh = 0; (ulong)atoi(ftc[12]); // This is the left hand item?
			charData.rh = 0; (ulong)atoi(ftc[13]); // This is the right hand item?
			charData.eyebrows = (ulong)atoi(ftc[14]); // Eyebrows
			charData.eyes = (ulong)atoi(ftc[15]); // Eyes
			charData.mouth = (ulong)atoi(ftc[16]); // Mouth
			charData.unknown4 = 0; // Dunno what this is...
			charData.lastZoneId = (ulong)atoi(ftc[25]); // The last world ID the user was in...
			charData.mapInstance = (ushort)atoi(ftc[26]); // The map instance
			charData.mapClone = (ulong)atoi(ftc[27]); // The map clone
			charData.lastLogout = 0; // Last logout in seconds (useless until we get world server working)
			//charData.equippedItemsLength = CharSpecialItemsCount(charData.objectID); // The items length

			charData.WriteDataToBitstream(&bitStream, i);

			GetCharSpecialItems(charData.objectID, &bitStream);
		}
	}	

	rakServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, systemAddress, false);
	SavePacket("char_creation.bin", (char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed());
}
void NatTypeDetectionServer::Update(void)
{
	int i=0;
	RakNet::TimeMS time = RakNet::GetTimeMS();
	RakNet::BitStream bs;
	SystemAddress boundAddress;

	// Only socket that receives messages is s3p4, to see if the external address is different than that of the connection to rakPeerInterface
	char data[ MAXIMUM_MTU_SIZE ];
	int len;
	SystemAddress senderAddr;
	len=NatTypeRecvFrom(data, s3p4, senderAddr);
	// Client is asking us if this is port restricted. Only client requests of this type come in on s3p4
	while (len>0 && data[0]==NAT_TYPE_PORT_RESTRICTED)
	{
		RakNet::BitStream bsIn((unsigned char*) data,len,false);
		RakNetGUID senderGuid;
		bsIn.IgnoreBytes(sizeof(MessageID));
		bool readSuccess = bsIn.Read(senderGuid);
		RakAssert(readSuccess);
		if (readSuccess)
		{
			unsigned int i = GetDetectionAttemptIndex(senderGuid);
			if (i!=(unsigned int)-1)
			{
				bs.Reset();
				bs.Write((unsigned char) ID_NAT_TYPE_DETECTION_RESULT);
				// If different, then symmetric
				if (senderAddr!=natDetectionAttempts[i].systemAddress)
				{
					printf("Determined client is symmetric\n");
					bs.Write((unsigned char) NAT_TYPE_SYMMETRIC);
				}
				else
				{
					// else port restricted
					printf("Determined client is port restricted\n");
					bs.Write((unsigned char) NAT_TYPE_PORT_RESTRICTED);
				}

				rakPeerInterface->Send(&bs,HIGH_PRIORITY,RELIABLE,0,natDetectionAttempts[i].systemAddress,false);

				// Done
				natDetectionAttempts.RemoveAtIndexFast(i);
			}
			else
			{
		//		RakAssert("i==0 in Update when looking up GUID in NatTypeDetectionServer.cpp. Either a bug or a late resend" && 0);
			}
		}
		else
		{
		//	RakAssert("Didn't read GUID in Update in NatTypeDetectionServer.cpp. Message format error" && 0);
		}

		len=NatTypeRecvFrom(data, s3p4, senderAddr);
	}


	while (i < (int) natDetectionAttempts.Size())
	{
		if (time > natDetectionAttempts[i].nextStateTime)
		{
			natDetectionAttempts[i].detectionState=(NATDetectionState)((int)natDetectionAttempts[i].detectionState+1);
			natDetectionAttempts[i].nextStateTime=time+natDetectionAttempts[i].timeBetweenAttempts;
			SystemAddress saOut;
			unsigned char c;
			bs.Reset();
			switch (natDetectionAttempts[i].detectionState)
			{
			case STATE_TESTING_NONE_1:
			case STATE_TESTING_NONE_2:
				c = NAT_TYPE_NONE;
				printf("Testing NAT_TYPE_NONE\n");
				// S4P5 sends to C2. If arrived, no NAT. Done. (Else S4P5 potentially banned, do not use again).
				saOut=natDetectionAttempts[i].systemAddress;
				saOut.SetPort(natDetectionAttempts[i].c2Port);
				SocketLayer::SendTo_PC( s4p5, (const char*) &c, 1, saOut, __FILE__, __LINE__  );
				break;
			case STATE_TESTING_FULL_CONE_1:
			case STATE_TESTING_FULL_CONE_2:
				printf("Testing NAT_TYPE_FULL_CONE\n");
				rakPeerInterface->WriteOutOfBandHeader(&bs);
				bs.Write((unsigned char) ID_NAT_TYPE_DETECT);
				bs.Write((unsigned char) NAT_TYPE_FULL_CONE);
				// S2P3 sends to C1 (Different address, different port, to previously used port on client). If received, Full-cone nat. Done.  (Else S2P3 potentially banned, do not use again).
				saOut=natDetectionAttempts[i].systemAddress;
				saOut.SetPort(natDetectionAttempts[i].systemAddress.GetPort());
				SocketLayer::SendTo_PC( s2p3, (const char*) bs.GetData(), bs.GetNumberOfBytesUsed(), saOut, __FILE__, __LINE__  );
				break;
			case STATE_TESTING_ADDRESS_RESTRICTED_1:
			case STATE_TESTING_ADDRESS_RESTRICTED_2:
				printf("Testing NAT_TYPE_ADDRESS_RESTRICTED\n");
				rakPeerInterface->WriteOutOfBandHeader(&bs);
				bs.Write((unsigned char) ID_NAT_TYPE_DETECT);
				bs.Write((unsigned char) NAT_TYPE_ADDRESS_RESTRICTED);
				// S1P2 sends to C1 (Same address, different port, to previously used port on client). If received, address-restricted cone nat. Done.
				saOut=natDetectionAttempts[i].systemAddress;
				saOut.SetPort(natDetectionAttempts[i].systemAddress.GetPort());
				SocketLayer::SendTo_PC( s1p2, (const char*) bs.GetData(), bs.GetNumberOfBytesUsed(), saOut, __FILE__, __LINE__  );
				break;
			case STATE_TESTING_PORT_RESTRICTED_1:
			case STATE_TESTING_PORT_RESTRICTED_2:
				// C1 sends to S3P4. If address of C1 as seen by S3P4 is the same as the address of C1 as seen by S1P1, then port-restricted cone nat. Done
				printf("Testing NAT_TYPE_PORT_RESTRICTED\n");
				bs.Write((unsigned char) ID_NAT_TYPE_DETECTION_REQUEST);
				bs.Write(RakString::NonVariadic(s3p4Address));
				bs.Write(s3p4Port);
				rakPeerInterface->Send(&bs,HIGH_PRIORITY,RELIABLE,0,natDetectionAttempts[i].systemAddress,false);
				break;
			default:
				printf("Warning, exceeded final check STATE_TESTING_PORT_RESTRICTED_2.\nExpected that client would have sent NAT_TYPE_PORT_RESTRICTED on s3p4.\nDefaulting to Symmetric\n");
				bs.Write((unsigned char) ID_NAT_TYPE_DETECTION_RESULT);
				bs.Write((unsigned char) NAT_TYPE_SYMMETRIC);
				rakPeerInterface->Send(&bs,HIGH_PRIORITY,RELIABLE,0,natDetectionAttempts[i].systemAddress,false);
				natDetectionAttempts.RemoveAtIndexFast(i);
				i--;
				break;
			}

		}
		i++;
	}
}
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();
}
PluginReceiveResult NatPunchthroughServer::OnReceive(Packet *packet)
{
	switch (packet->data[0])
	{
	case ID_NAT_PUNCHTHROUGH_REQUEST:
		OnNATPunchthroughRequest(packet);
		return RR_STOP_PROCESSING_AND_DEALLOCATE;
	case ID_NAT_GET_MOST_RECENT_PORT:
		OnGetMostRecentPort(packet);
		return RR_STOP_PROCESSING_AND_DEALLOCATE;
	case ID_NAT_CLIENT_READY:
		OnClientReady(packet);
		return RR_STOP_PROCESSING_AND_DEALLOCATE;
	case ID_NAT_REQUEST_BOUND_ADDRESSES:
		{
			RakNet::BitStream outgoingBs;
			outgoingBs.Write((MessageID)ID_NAT_RESPOND_BOUND_ADDRESSES);
			
			if (boundAddresses[0]==UNASSIGNED_SYSTEM_ADDRESS)
			{
				DataStructures::List<RakNetSocket2* > sockets;
				rakPeerInterface->GetSockets(sockets);
				for (int i=0; i < sockets.Size() && i < MAXIMUM_NUMBER_OF_INTERNAL_IDS; i++)
				{
					boundAddresses[i]=sockets[i]->GetBoundAddress();
					boundAddressCount++;
				}
			}

			outgoingBs.Write(boundAddressCount);
			for (int i=0; i < boundAddressCount; i++)
			{
				outgoingBs.Write(boundAddresses[i]);
			}

			rakPeerInterface->Send(&outgoingBs,HIGH_PRIORITY,RELIABLE_ORDERED,0,packet->systemAddress,false);
		}
		return RR_STOP_PROCESSING_AND_DEALLOCATE;
	case ID_NAT_PING:
		{
		}
		return RR_STOP_PROCESSING_AND_DEALLOCATE;
	case ID_OUT_OF_BAND_INTERNAL:
		if (packet->length>=2 && packet->data[1]==ID_NAT_PING)
		{
			RakNet::BitStream bs(packet->data,packet->length,false);
			bs.IgnoreBytes(sizeof(MessageID)*2);
			uint16_t externalPort;
			bs.Read(externalPort);

			RakNet::BitStream outgoingBs;
			outgoingBs.Write((MessageID)ID_NAT_PONG);
			outgoingBs.Write(externalPort);
			uint16_t externalPort2 = packet->systemAddress.GetPort();
			outgoingBs.Write(externalPort2);
			rakPeerInterface->SendOutOfBand((const char*) packet->systemAddress.ToString(false),packet->systemAddress.GetPort(),(const char*) outgoingBs.GetData(),outgoingBs.GetNumberOfBytesUsed());

			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		}
	}
	return RR_CONTINUE_PROCESSING;
}
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);
	}
}
PluginReceiveResult NatPunchthroughClient::OnReceive(Packet *packet)
{
	switch (packet->data[0])
	{
	case ID_NAT_GET_MOST_RECENT_PORT:
		{
			OnGetMostRecentPort(packet);
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		}
	case ID_NAT_PUNCHTHROUGH_FAILED:
	case ID_NAT_PUNCHTHROUGH_SUCCEEDED:
		if (packet->wasGeneratedLocally==false)
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		break;
	case ID_NAT_RESPOND_BOUND_ADDRESSES:
		{
			RakNet::BitStream bs(packet->data,packet->length,false);
			bs.IgnoreBytes(sizeof(MessageID));
			unsigned char boundAddressCount;
			bs.Read(boundAddressCount);
			if (boundAddressCount<2)
			{
				if (natPunchthroughDebugInterface)
					natPunchthroughDebugInterface->OnClientMessage("INCAPABLE_PORT_STRIDE");

				hasPortStride=INCAPABLE_PORT_STRIDE;
				SendQueuedOpenNAT();
			}
			SystemAddress boundAddresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS];
			for (int i=0; i < boundAddressCount && i < MAXIMUM_NUMBER_OF_INTERNAL_IDS; i++)
			{
				bs.Read(boundAddresses[i]);
				if (boundAddresses[i]!=packet->systemAddress)
				{
					RakNet::BitStream outgoingBs;
					outgoingBs.Write((MessageID)ID_NAT_PING);
					uint16_t externalPort = rakPeerInterface->GetExternalID(packet->systemAddress).GetPort();
					outgoingBs.Write( externalPort );
					rakPeerInterface->SendOutOfBand((const char*) boundAddresses[i].ToString(false),boundAddresses[i].GetPort(),(const char*) outgoingBs.GetData(),outgoingBs.GetNumberOfBytesUsed());
					break;
				}
			}
		}
		break;		
	case ID_OUT_OF_BAND_INTERNAL:
		if (packet->length>=2 && packet->data[1]==ID_NAT_PONG)
		{
			RakNet::BitStream bs(packet->data,packet->length,false);
			bs.IgnoreBytes(sizeof(MessageID)*2);
			uint16_t externalPort;
			bs.Read(externalPort);
			uint16_t externalPort2;
			bs.Read(externalPort2);
			portStride = externalPort2 - externalPort;
			hasPortStride=HAS_PORT_STRIDE;

			if (natPunchthroughDebugInterface)
				natPunchthroughDebugInterface->OnClientMessage(RakString("HAS_PORT_STRIDE %i. Server first external port %i. Server second external port %i.", portStride, externalPort, externalPort2));

			SendQueuedOpenNAT();
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		}
		else if (packet->length>=2 &&
			(packet->data[1]==ID_NAT_ESTABLISH_UNIDIRECTIONAL || packet->data[1]==ID_NAT_ESTABLISH_BIDIRECTIONAL) &&
			sp.nextActionTime!=0)
		{
			RakNet::BitStream bs(packet->data,packet->length,false);
			bs.IgnoreBytes(2);
			uint16_t sessionId;
			bs.Read(sessionId);
//			RakAssert(sessionId<100);
			if (sessionId!=sp.sessionId)
				break;

			char ipAddressString[32];
			packet->systemAddress.ToString(true,ipAddressString);
			// sp.targetGuid==packet->guid is because the internal IP addresses reported may include loopbacks not reported by RakPeer::IsLocalIP()
			if (packet->data[1]==ID_NAT_ESTABLISH_UNIDIRECTIONAL && sp.targetGuid==packet->guid)
			{
				if (natPunchthroughDebugInterface)
				{
					char guidString[128];
					sp.targetGuid.ToString(guidString);
					natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Received ID_NAT_ESTABLISH_UNIDIRECTIONAL from guid %s, system address %s.", guidString, ipAddressString));
				}
				if (sp.testMode!=SendPing::PUNCHING_FIXED_PORT)
				{
					sp.testMode=SendPing::PUNCHING_FIXED_PORT;
					sp.retryCount+=sp.attemptCount*pc.UDP_SENDS_PER_PORT_EXTERNAL;
					sp.targetAddress=packet->systemAddress;
					// Keeps trying until the other side gives up too, in case it is unidirectional
					sp.punchingFixedPortAttempts=pc.UDP_SENDS_PER_PORT_EXTERNAL*(pc.MAX_PREDICTIVE_PORT_RANGE+1);
				}

				SendOutOfBand(sp.targetAddress,ID_NAT_ESTABLISH_BIDIRECTIONAL);
			}
			else if (packet->data[1]==ID_NAT_ESTABLISH_BIDIRECTIONAL &&
				sp.targetGuid==packet->guid)
			{
				// They send back our port
				unsigned short ourExternalPort;
				bs.Read(ourExternalPort);
				if (nextExternalPort==0)
				{
					nextExternalPort=ourExternalPort;
				}
				else
				{
					if (sp.testMode!=SendPing::TESTING_INTERNAL_IPS && sp.testMode!=SendPing::WAITING_FOR_INTERNAL_IPS_RESPONSE)
					{
						if (hasPortStride!=HAS_PORT_STRIDE)
						{
							portStride = ourExternalPort - nextExternalPort;
							hasPortStride=HAS_PORT_STRIDE;

							if (natPunchthroughDebugInterface)
							{
								natPunchthroughDebugInterface->OnClientMessage(RakString("Estimated port stride from incoming connection at %i", portStride));
							}

							SendQueuedOpenNAT();
						}

						nextExternalPort += portStride * (pc.MAX_PREDICTIVE_PORT_RANGE+1);

						if (natPunchthroughDebugInterface)
						{
							natPunchthroughDebugInterface->OnClientMessage(RakString("Estimated next external port %i", nextExternalPort));
						}
					}
				}
				SendOutOfBand(packet->systemAddress,ID_NAT_ESTABLISH_BIDIRECTIONAL);

				// Tell the user about the success
				sp.targetAddress=packet->systemAddress;
				PushSuccess();
				//UpdateGroupPunchOnNatResult(sp.facilitator, sp.targetGuid, sp.targetAddress, 1);
				OnReadyForNextPunchthrough();
				bool removedFromFailureQueue=RemoveFromFailureQueue();

				if (natPunchthroughDebugInterface)
				{
					char guidString[128];
					sp.targetGuid.ToString(guidString);
					if (removedFromFailureQueue)
						natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough to guid %s, system address %s succeeded on 2nd attempt.", guidString, ipAddressString));
					else
						natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough to guid %s, system address %s succeeded on 1st attempt.", guidString, ipAddressString));
				}
			}

	//		mostRecentNewExternalPort=packet->systemAddress.GetPort();
		}
		return RR_STOP_PROCESSING_AND_DEALLOCATE;
	case ID_NAT_ALREADY_IN_PROGRESS:
		{
			RakNet::BitStream incomingBs(packet->data, packet->length, false);
			incomingBs.IgnoreBytes(sizeof(MessageID));
			RakNetGUID targetGuid;
			incomingBs.Read(targetGuid);
			// Don't update group, just use later message
			// UpdateGroupPunchOnNatResult(packet->systemAddress, targetGuid, UNASSIGNED_SYSTEM_ADDRESS, 2);
			if (natPunchthroughDebugInterface)
			{
				char guidString[128];
				targetGuid.ToString(guidString);
				natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough retry to guid %s failed due to ID_NAT_ALREADY_IN_PROGRESS. Returning failure.", guidString));
			}

		}
		break;
	case ID_NAT_TARGET_NOT_CONNECTED:
	case ID_NAT_CONNECTION_TO_TARGET_LOST:
	case ID_NAT_TARGET_UNRESPONSIVE:
		{
			const char *reason;
			if (packet->data[0]==ID_NAT_TARGET_NOT_CONNECTED)
				reason=(char *)"ID_NAT_TARGET_NOT_CONNECTED";
			else if (packet->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST)
				reason=(char *)"ID_NAT_CONNECTION_TO_TARGET_LOST";
			else
				reason=(char *)"ID_NAT_TARGET_UNRESPONSIVE";


			RakNet::BitStream incomingBs(packet->data, packet->length, false);
			incomingBs.IgnoreBytes(sizeof(MessageID));

			RakNetGUID targetGuid;
			incomingBs.Read(targetGuid);
			//UpdateGroupPunchOnNatResult(packet->systemAddress, targetGuid, UNASSIGNED_SYSTEM_ADDRESS, 2);

			if (packet->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST ||
				packet->data[0]==ID_NAT_TARGET_UNRESPONSIVE)
			{
				uint16_t sessionId;
				incomingBs.Read(sessionId);
				if (sessionId!=sp.sessionId)
					break;
			}

			unsigned int i;
			for (i=0; i < failedAttemptList.Size(); i++)
			{
				if (failedAttemptList[i].guid==targetGuid)
				{
					if (natPunchthroughDebugInterface)
					{
						char guidString[128];
						targetGuid.ToString(guidString);
						natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough retry to guid %s failed due to %s.", guidString, reason));

					}

					// If the retry target is not connected, or loses connection, or is not responsive, then previous failures cannot be retried.

					// Don't need to return failed, the other messages indicate failure anyway
					/*
					Packet *p = AllocatePacketUnified(sizeof(MessageID));
					p->data[0]=ID_NAT_PUNCHTHROUGH_FAILED;
					p->systemAddress=failedAttemptList[i].addr;
					p->systemAddress.systemIndex=(SystemIndex)-1;
					p->guid=failedAttemptList[i].guid;
					rakPeerInterface->PushBackPacket(p, false);
					*/

					failedAttemptList.RemoveAtIndexFast(i);
					break;
				}
			}

			if (natPunchthroughDebugInterface)
			{
				char guidString[128];
				targetGuid.ToString(guidString);
				natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough attempt to guid %s failed due to %s.", guidString, reason));
			}

			// Stop trying punchthrough
			sp.nextActionTime=0;

			/*
			RakNet::BitStream bs(packet->data, packet->length, false);
			bs.IgnoreBytes(sizeof(MessageID));
			RakNetGUID failedSystem;
			bs.Read(failedSystem);
			bool deletedFirst=false;
			unsigned int i=0;
			while (i < pendingOpenNAT.Size())
			{
				if (pendingOpenNAT[i].destination==failedSystem)
				{
					if (i==0)
						deletedFirst=true;
					pendingOpenNAT.RemoveAtIndex(i);
				}
				else
					i++;
			}
			// Failed while in progress. Go to next in attempt queue
			if (deletedFirst && pendingOpenNAT.Size())
			{
				SendPunchthrough(pendingOpenNAT[0].destination, pendingOpenNAT[0].facilitator);
				sp.nextActionTime=0;
			}
			*/
		}
		break;
	case ID_TIMESTAMP:
		if (packet->data[sizeof(MessageID)+sizeof(RakNet::Time)]==ID_NAT_CONNECT_AT_TIME)
		{
			OnConnectAtTime(packet);
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		}
		break;
	}
	return RR_CONTINUE_PROCESSING;
}
void SendStatusPacket(RakPeerInterface *rakServer, const SystemAddress& systemAddress, UserSuccess loginStatus, string redirectIpAddress, ushort redirectPort, ushort extraDataLength) {
	RakNet::BitStream bitStream; // Create the bitStream

	// Always create the packet header
	CreatePacketHeader(ID_USER_PACKET_ENUM, 5, 0, &bitStream);

	LoginStatusPacket loginStatusPacket;

	// Set the loginStatus
	loginStatusPacket.loginStatus = loginStatus;

	// Set Talk_Like_A_Pirate_String
	loginStatusPacket.talkLikeAPirate = "Talk_Like_A_Pirate";
	loginStatusPacket.unknownString = "";

	// Set client version
	loginStatusPacket.clientVersion1 = 1;
	loginStatusPacket.clientVersion2 = 10;
	loginStatusPacket.clientVersion3 = 64;

	// This is unknown data...
	loginStatusPacket.unknown = "_";

	time_t t = time(NULL);
	unsigned int addr = systemAddress.binaryAddress;
	long long a = (long long)t * (long long)addr;
	std::string hash = md5(std::to_string(a));
	std::wstring key = StringToWString(hash, 33);

	// Get the user key
	loginStatusPacket.userKey = key;
	//loginStatusPacket.userKey = "0 9 4 e 7 0 1 a c 3 b 5 5 2 0 b 4 7 8 9 5 b 3 1 8 5 7 b f 1 c 3   ";

	// Set chat IPs/Port and the other IP
	loginStatusPacket.chatIp = "192.168.0.20"; //TODO: make dynamic
	loginStatusPacket.chatPort = 2003;
	loginStatusPacket.anotherIp = "192.168.0.20";

	loginStatusPacket.possibleGuid = "00000000-0000-0000-0000-000000000000";

	loginStatusPacket.zeroLong = 0;

	// Set localization
	loginStatusPacket.localizationChar[0] = 0x55;
	loginStatusPacket.localizationChar[1] = 0x53;
	loginStatusPacket.localizationChar[2] = 0x00;

	// Subscribed?
	loginStatusPacket.firstLoginSubscription = 1;
	loginStatusPacket.subscribed = 0;

	loginStatusPacket.zeroLongLong = 0;

	loginStatusPacket.redirectIp = redirectIpAddress;
	loginStatusPacket.redirectPort = redirectPort;

	// Sett the error msg and the error msg length
	// This message only shows
	loginStatusPacket.errorMsg = "";
	loginStatusPacket.errorMsgLength = loginStatusPacket.errorMsg.length();

	// Set the extraBytesLength to the one the user defined
	loginStatusPacket.extraBytesLength = extraDataLength;

	// ---- CREATE BITSTREAM ---- //
	// Write the connectionId to bitStream
	bitStream.Write(loginStatusPacket.loginStatus);

	// Write the "Talk_Like_A_Pirate" string to bitStream
	WriteStringToBitStream(loginStatusPacket.talkLikeAPirate.c_str(), 18, 33, &bitStream);

	// Write 7 blocks of data (length: 33) to bitStream
	// In the original login_status_ok.bin, these sometimes ended in
	// bytes other than 0x00, but losing that doesn't seem to have much of an effect... yet.
	for (int i = 0; i < 7; i++) {
		WriteStringToBitStream(loginStatusPacket.unknownString.c_str(), 0, 33, &bitStream);
	}

	// Write the clientVersion to bitStream (all 3 parts)
	bitStream.Write(loginStatusPacket.clientVersion1);
	bitStream.Write(loginStatusPacket.clientVersion2);
	bitStream.Write(loginStatusPacket.clientVersion3);

	// Write the userKey, redirectIp, and chatIp to bitStream
	//WriteStringToBitStream(loginStatusPacket.userKey.c_str(), 66, 66, &bitStream);
	PacketTools::WriteToPacket(&bitStream, loginStatusPacket.userKey, 33);
	WriteStringToBitStream(loginStatusPacket.redirectIp.c_str(), sizeof(loginStatusPacket.redirectIp), 33, &bitStream);
	WriteStringToBitStream(loginStatusPacket.chatIp.c_str(), sizeof(loginStatusPacket.chatIp), 33, &bitStream);
	
	// Write the redirectPort and the chatPort to bitStream
	bitStream.Write(loginStatusPacket.redirectPort);
	bitStream.Write(loginStatusPacket.chatPort);
	
	// Write seperate ip(?) and possibleGuid to bitStream
	WriteStringToBitStream(loginStatusPacket.anotherIp.c_str(), sizeof(loginStatusPacket.anotherIp), 33, &bitStream);
	WriteStringToBitStream(loginStatusPacket.possibleGuid.c_str(), 37, 37, &bitStream);
	
	// Write the zeroShort to the errorMsgLength to the bitStream
	bitStream.Write(loginStatusPacket.zeroLong);
	bitStream.Write(loginStatusPacket.localizationChar[0]);
	bitStream.Write(loginStatusPacket.localizationChar[1]);
	bitStream.Write(loginStatusPacket.localizationChar[2]);
	bitStream.Write(loginStatusPacket.firstLoginSubscription);
	bitStream.Write(loginStatusPacket.subscribed);
	bitStream.Write(loginStatusPacket.zeroLongLong);
	bitStream.Write(loginStatusPacket.errorMsgLength);
	
	// Write the error msg string to the bitStream
	WriteStringToBitStream(loginStatusPacket.errorMsg.c_str(), loginStatusPacket.errorMsgLength, 0, &bitStream);
	
	// Add extra bytes length
	bitStream.Write(loginStatusPacket.extraBytesLength);

	// Create extra packet data (even if not success, doesn't appear to
	// Do anything at the moment...)
	CreateExtraPacketDataSuccess(&bitStream);

	rakServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE_ORDERED, 0, systemAddress, false);
	SavePacketOverwrite("test_login.bin", (char*)bitStream.GetData(), bitStream.GetNumberOfBytesUsed());
}