#include "NativeFeatureIncludes.h"
#if _RAKNET_SUPPORT_UDPProxyCoordinator==1 && _RAKNET_SUPPORT_UDPForwarder==1

#include "UDPProxyCoordinator.h"
#include "BitStream.h"
#include "UDPProxyCommon.h"
#include "RakPeerInterface.h"
#include "MessageIdentifiers.h"
#include "Rand.h"
#include "GetTime.h"
#include "UDPForwarder.h"

// Larger than the client version
static const int DEFAULT_CLIENT_UNRESPONSIVE_PING_TIME=2000;
static const int DEFAULT_UNRESPONSIVE_PING_TIME=DEFAULT_CLIENT_UNRESPONSIVE_PING_TIME+1000;

using namespace RakNet;

// bool operator<( const DataStructures::MLKeyRef<unsigned short> &inputKey, const UDPProxyCoordinator::ServerWithPing &cls ) {return inputKey.Get() < cls.ping;}
// bool operator>( const DataStructures::MLKeyRef<unsigned short> &inputKey, const UDPProxyCoordinator::ServerWithPing &cls ) {return inputKey.Get() > cls.ping;}
// bool operator==( const DataStructures::MLKeyRef<unsigned short> &inputKey, const UDPProxyCoordinator::ServerWithPing &cls ) {return inputKey.Get() == cls.ping;}

int UDPProxyCoordinator::ServerWithPingComp( const unsigned short &key, const UDPProxyCoordinator::ServerWithPing &data )
{
	if (key < data.ping)
		return -1;
	if (key > data.ping)
		return 1;
	return 0;
}

int UDPProxyCoordinator::ForwardingRequestComp( const SenderAndTargetAddress &key, ForwardingRequest* const &data)
{
	if (key.senderClientAddress < data->sata.senderClientAddress )
		return -1;
	if (key.senderClientAddress > data->sata.senderClientAddress )
		return -1;
	if (key.targetClientAddress < data->sata.targetClientAddress )
		return -1;
	if (key.targetClientAddress > data->sata.targetClientAddress )
		return 1;
	return 0;
}
// 
// bool operator<( const DataStructures::MLKeyRef<UDPProxyCoordinator::SenderAndTargetAddress> &inputKey, const UDPProxyCoordinator::ForwardingRequest *cls )
// {
// 	return inputKey.Get().senderClientAddress < cls->sata.senderClientAddress ||
// 		(inputKey.Get().senderClientAddress == cls->sata.senderClientAddress && inputKey.Get().targetClientAddress < cls->sata.targetClientAddress);
// }
// bool operator>( const DataStructures::MLKeyRef<UDPProxyCoordinator::SenderAndTargetAddress> &inputKey, const UDPProxyCoordinator::ForwardingRequest *cls )
// {
// 	return inputKey.Get().senderClientAddress > cls->sata.senderClientAddress ||
// 		(inputKey.Get().senderClientAddress == cls->sata.senderClientAddress && inputKey.Get().targetClientAddress > cls->sata.targetClientAddress);
// }
// bool operator==( const DataStructures::MLKeyRef<UDPProxyCoordinator::SenderAndTargetAddress> &inputKey, const UDPProxyCoordinator::ForwardingRequest *cls )
// {
// 	return inputKey.Get().senderClientAddress == cls->sata.senderClientAddress && inputKey.Get().targetClientAddress == cls->sata.targetClientAddress;
// }

STATIC_FACTORY_DEFINITIONS(UDPProxyCoordinator,UDPProxyCoordinator);

UDPProxyCoordinator::UDPProxyCoordinator()
{

}
UDPProxyCoordinator::~UDPProxyCoordinator()
{
	Clear();
}
void UDPProxyCoordinator::SetRemoteLoginPassword(RakNet::RakString password)
{
	remoteLoginPassword=password;
}
void UDPProxyCoordinator::Update(void)
{
	unsigned int idx;
	RakNet::TimeMS curTime = RakNet::GetTimeMS();
	ForwardingRequest *fw;
	idx=0;
	while (idx < forwardingRequestList.Size())
	{
		fw=forwardingRequestList[idx];
		if (fw->timeRequestedPings!=0 &&
			curTime > fw->timeRequestedPings + DEFAULT_UNRESPONSIVE_PING_TIME)
		{
			fw->OrderRemainingServersToTry();
			fw->timeRequestedPings=0;
			TryNextServer(fw->sata, fw);
			idx++;
		}
		else if (fw->timeoutAfterSuccess!=0 &&
			curTime > fw->timeoutAfterSuccess)
		{
			// Forwarding request succeeded, we waited a bit to prevent duplicates. Can forget about the entry now.
			RakNet::OP_DELETE(fw,_FILE_AND_LINE_);
			forwardingRequestList.RemoveAtIndex(idx);
		}
		else
			idx++;
	}
}
PluginReceiveResult UDPProxyCoordinator::OnReceive(Packet *packet)
{
	if (packet->data[0]==ID_UDP_PROXY_GENERAL && packet->length>1)
	{
		switch (packet->data[1])
		{
		case ID_UDP_PROXY_FORWARDING_REQUEST_FROM_CLIENT_TO_COORDINATOR:
			OnForwardingRequestFromClientToCoordinator(packet);
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		case ID_UDP_PROXY_LOGIN_REQUEST_FROM_SERVER_TO_COORDINATOR:
			OnLoginRequestFromServerToCoordinator(packet);
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		case ID_UDP_PROXY_FORWARDING_REPLY_FROM_SERVER_TO_COORDINATOR:
			OnForwardingReplyFromServerToCoordinator(packet);
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		case ID_UDP_PROXY_PING_SERVERS_REPLY_FROM_CLIENT_TO_COORDINATOR:
			OnPingServersReplyFromClientToCoordinator(packet);
			return RR_STOP_PROCESSING_AND_DEALLOCATE;
		}
	}
	return RR_CONTINUE_PROCESSING;
}
void UDPProxyCoordinator::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
{
	(void) lostConnectionReason;
	(void) rakNetGUID;

	unsigned int idx, idx2;

	idx=0;
	while (idx < forwardingRequestList.Size())
	{
		if (forwardingRequestList[idx]->requestingAddress==systemAddress)
		{
			// Guy disconnected before the attempt completed
			RakNet::OP_DELETE(forwardingRequestList[idx], _FILE_AND_LINE_);
			forwardingRequestList.RemoveAtIndex(idx );
		}
		else
			idx++;
	}

	idx = serverList.GetIndexOf(systemAddress);
	if (idx!=(unsigned int)-1)
	{
		ForwardingRequest *fw;
		// For each pending client for this server, choose from remaining servers.
		for (idx2=0; idx2 < forwardingRequestList.Size(); idx2++)
		{
			fw = forwardingRequestList[idx2];
			if (fw->currentlyAttemptedServerAddress==systemAddress)
			{
				// Try the next server
				TryNextServer(fw->sata, fw);
			}
		}

		// Remove dead server
		serverList.RemoveAtIndexFast(idx);
	}
}
void UDPProxyCoordinator::OnForwardingRequestFromClientToCoordinator(Packet *packet)
{
	RakNet::BitStream incomingBs(packet->data, packet->length, false);
	incomingBs.IgnoreBytes(2);
	SystemAddress sourceAddress;
	incomingBs.Read(sourceAddress);
	if (sourceAddress==UNASSIGNED_SYSTEM_ADDRESS)
		sourceAddress=packet->systemAddress;
	SystemAddress targetAddress;
	RakNetGUID targetGuid;
	bool usesAddress=false;
	incomingBs.Read(usesAddress);
	if (usesAddress)
	{
		incomingBs.Read(targetAddress);
		targetGuid=rakPeerInterface->GetGuidFromSystemAddress(targetAddress);
	}
	else
	{
		incomingBs.Read(targetGuid);
		targetAddress=rakPeerInterface->GetSystemAddressFromGuid(targetGuid);
	}
	ForwardingRequest *fw = RakNet::OP_NEW<ForwardingRequest>(_FILE_AND_LINE_);
	fw->timeoutAfterSuccess=0;
	incomingBs.Read(fw->timeoutOnNoDataMS);
	bool hasServerSelectionBitstream=false;
	incomingBs.Read(hasServerSelectionBitstream);
	if (hasServerSelectionBitstream)
		incomingBs.Read(&(fw->serverSelectionBitstream));

	RakNet::BitStream outgoingBs;
	SenderAndTargetAddress sata;
	sata.senderClientAddress=sourceAddress;
	sata.targetClientAddress=targetAddress;
	sata.targetClientGuid=targetGuid;
	sata.senderClientGuid=rakPeerInterface->GetGuidFromSystemAddress(sourceAddress);
	SenderAndTargetAddress sataReversed;
	sataReversed.senderClientAddress=targetAddress;
	sataReversed.targetClientAddress=sourceAddress;
	sataReversed.senderClientGuid=sata.targetClientGuid;
	sataReversed.targetClientGuid=sata.senderClientGuid;

	unsigned int insertionIndex;
	bool objectExists1, objectExists2;
	insertionIndex=forwardingRequestList.GetIndexFromKey(sata, &objectExists1);
	forwardingRequestList.GetIndexFromKey(sataReversed, &objectExists2);

	if (objectExists1 || objectExists2)
	{
		outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
		outgoingBs.Write((MessageID)ID_UDP_PROXY_IN_PROGRESS);
		outgoingBs.Write(sata.senderClientAddress);
		outgoingBs.Write(targetAddress);
		outgoingBs.Write(targetGuid);
		rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
		RakNet::OP_DELETE(fw, _FILE_AND_LINE_);
		return;
	}

	if (serverList.Size()==0)
	{
		outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
		outgoingBs.Write((MessageID)ID_UDP_PROXY_NO_SERVERS_ONLINE);
		outgoingBs.Write(sata.senderClientAddress);
		outgoingBs.Write(targetAddress);
		outgoingBs.Write(targetGuid);
		rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
		RakNet::OP_DELETE(fw, _FILE_AND_LINE_);
		return;
	}

	if (rakPeerInterface->GetConnectionState(targetAddress)!=IS_CONNECTED && usesAddress==false)
	{
		outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
		outgoingBs.Write((MessageID)ID_UDP_PROXY_RECIPIENT_GUID_NOT_CONNECTED_TO_COORDINATOR);
		outgoingBs.Write(sata.senderClientAddress);
		outgoingBs.Write(targetAddress);
		outgoingBs.Write(targetGuid);
		rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
		RakNet::OP_DELETE(fw, _FILE_AND_LINE_);
		return;
	}

	fw->sata=sata;
	fw->requestingAddress=packet->systemAddress;

	if (serverList.Size()>1)
	{
		outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
		outgoingBs.Write((MessageID)ID_UDP_PROXY_PING_SERVERS_FROM_COORDINATOR_TO_CLIENT);
		outgoingBs.Write(sourceAddress);
		outgoingBs.Write(targetAddress);
		outgoingBs.Write(targetGuid);
		unsigned short serverListSize = (unsigned short) serverList.Size();
		outgoingBs.Write(serverListSize);
		unsigned int idx;
		for (idx=0; idx < serverList.Size(); idx++)
			outgoingBs.Write(serverList[idx]);
		rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, sourceAddress, false);
		rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, targetAddress, false);
		fw->timeRequestedPings=RakNet::GetTimeMS();
		unsigned int copyIndex;
		for (copyIndex=0; copyIndex < serverList.Size(); copyIndex++)
			fw->remainingServersToTry.Push(serverList[copyIndex], _FILE_AND_LINE_ );
		forwardingRequestList.InsertAtIndex(fw, insertionIndex, _FILE_AND_LINE_ );
	}
	else
	{
		fw->timeRequestedPings=0;
		fw->currentlyAttemptedServerAddress=serverList[0];
		forwardingRequestList.InsertAtIndex(fw, insertionIndex, _FILE_AND_LINE_ );
		SendForwardingRequest(sourceAddress, targetAddress, fw->currentlyAttemptedServerAddress, fw->timeoutOnNoDataMS);
	}
}

void UDPProxyCoordinator::SendForwardingRequest(SystemAddress sourceAddress, SystemAddress targetAddress, SystemAddress serverAddress, RakNet::TimeMS timeoutOnNoDataMS)
{
	RakNet::BitStream outgoingBs;
	// Send request to desired server
	outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
	outgoingBs.Write((MessageID)ID_UDP_PROXY_FORWARDING_REQUEST_FROM_COORDINATOR_TO_SERVER);
	outgoingBs.Write(sourceAddress);
	outgoingBs.Write(targetAddress);
	outgoingBs.Write(timeoutOnNoDataMS);
	rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, serverAddress, false);
}
void UDPProxyCoordinator::OnLoginRequestFromServerToCoordinator(Packet *packet)
{
	RakNet::BitStream incomingBs(packet->data, packet->length, false);
	incomingBs.IgnoreBytes(2);
	RakNet::RakString password;
	incomingBs.Read(password);
	RakNet::BitStream outgoingBs;

	if (remoteLoginPassword.IsEmpty())
	{
		outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
		outgoingBs.Write((MessageID)ID_UDP_PROXY_NO_PASSWORD_SET_FROM_COORDINATOR_TO_SERVER);
		outgoingBs.Write(password);
		rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
		return;
	}

	if (remoteLoginPassword!=password)
	{
		outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
		outgoingBs.Write((MessageID)ID_UDP_PROXY_WRONG_PASSWORD_FROM_COORDINATOR_TO_SERVER);
		outgoingBs.Write(password);
		rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
		return;
	}

	unsigned int insertionIndex;
	insertionIndex=serverList.GetIndexOf(packet->systemAddress);
	if (insertionIndex!=(unsigned int)-1)
	{
		outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
		outgoingBs.Write((MessageID)ID_UDP_PROXY_ALREADY_LOGGED_IN_FROM_COORDINATOR_TO_SERVER);
		outgoingBs.Write(password);
		rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
		return;
	}
	serverList.Push(packet->systemAddress, _FILE_AND_LINE_ );
	outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
	outgoingBs.Write((MessageID)ID_UDP_PROXY_LOGIN_SUCCESS_FROM_COORDINATOR_TO_SERVER);
	outgoingBs.Write(password);
	rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, packet->systemAddress, false);
}
void UDPProxyCoordinator::OnForwardingReplyFromServerToCoordinator(Packet *packet)
{
	RakNet::BitStream incomingBs(packet->data, packet->length, false);
	incomingBs.IgnoreBytes(2);
	SenderAndTargetAddress sata;
	incomingBs.Read(sata.senderClientAddress);
	incomingBs.Read(sata.targetClientAddress);
	bool objectExists;
	unsigned int index = forwardingRequestList.GetIndexFromKey(sata, &objectExists);
	if (objectExists==false)
	{
		// The guy disconnected before the request finished
		return;
	}
	ForwardingRequest *fw = forwardingRequestList[index];
	sata.senderClientGuid = fw->sata.senderClientGuid;
	sata.targetClientGuid = fw->sata.targetClientGuid;

	UDPForwarderResult success;
	unsigned char c;
	incomingBs.Read(c);
	success=(UDPForwarderResult)c;

	RakNet::BitStream outgoingBs;
	if (success==UDPFORWARDER_SUCCESS)
	{
		char serverIP[64];
		packet->systemAddress.ToString(false,serverIP);
		unsigned short forwardingPort;
		incomingBs.Read(forwardingPort);

		outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
		outgoingBs.Write((MessageID)ID_UDP_PROXY_FORWARDING_SUCCEEDED);
		outgoingBs.Write(sata.senderClientAddress);
		outgoingBs.Write(sata.targetClientAddress);
		outgoingBs.Write(sata.targetClientGuid);
		outgoingBs.Write(RakNet::RakString(serverIP));
		outgoingBs.Write(forwardingPort);
		rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, fw->requestingAddress, false);

		outgoingBs.Reset();
		outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
		outgoingBs.Write((MessageID)ID_UDP_PROXY_FORWARDING_NOTIFICATION);
		outgoingBs.Write(sata.senderClientAddress);
		outgoingBs.Write(sata.targetClientAddress);
		outgoingBs.Write(sata.targetClientGuid);
		outgoingBs.Write(RakNet::RakString(serverIP));
		outgoingBs.Write(forwardingPort);
		rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, sata.targetClientAddress, false);

		// 05/18/09 Keep the entry around for some time after success, so duplicates are reported if attempting forwarding from the target system before notification of success
		fw->timeoutAfterSuccess=RakNet::GetTimeMS()+fw->timeoutOnNoDataMS;
		// forwardingRequestList.RemoveAtIndex(index);
		// RakNet::OP_DELETE(fw,_FILE_AND_LINE_);

		return;
	}
	else if (success==UDPFORWARDER_NO_SOCKETS)
	{
		// Try next server
		TryNextServer(sata, fw);
	}
	else
	{
		RakAssert(success==UDPFORWARDER_FORWARDING_ALREADY_EXISTS);

		// Return in progress
		outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
		outgoingBs.Write((MessageID)ID_UDP_PROXY_IN_PROGRESS);
		outgoingBs.Write(sata.senderClientAddress);
		outgoingBs.Write(sata.targetClientAddress);
		outgoingBs.Write(sata.targetClientGuid);
		rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, fw->requestingAddress, false);
		forwardingRequestList.RemoveAtIndex(index);
		RakNet::OP_DELETE(fw,_FILE_AND_LINE_);
	}
}
void UDPProxyCoordinator::OnPingServersReplyFromClientToCoordinator(Packet *packet)
{
	RakNet::BitStream incomingBs(packet->data, packet->length, false);
	incomingBs.IgnoreBytes(2);
	unsigned short serversToPingSize;
	SystemAddress serverAddress;
	SenderAndTargetAddress sata;
	incomingBs.Read(sata.senderClientAddress);
	incomingBs.Read(sata.targetClientAddress);
	bool objectExists;
	unsigned int index = forwardingRequestList.GetIndexFromKey(sata, &objectExists);
	if (objectExists==false)
		return;
	unsigned short idx;
	ServerWithPing swp;
	ForwardingRequest *fw = forwardingRequestList[index];
	if (fw->timeRequestedPings==0)
		return;

	incomingBs.Read(serversToPingSize);
	if (packet->systemAddress==sata.senderClientAddress)
	{
		for (idx=0; idx < serversToPingSize; idx++)
		{
			incomingBs.Read(swp.serverAddress);
			incomingBs.Read(swp.ping);
			unsigned int index2;
			for (index2=0; index2 < fw->sourceServerPings.Size(); index2++)
			{
				if (fw->sourceServerPings[index2].ping >= swp.ping )
					break;
			}
			fw->sourceServerPings.Insert(swp, index2, _FILE_AND_LINE_);
		}
	}
	else
	{
		for (idx=0; idx < serversToPingSize; idx++)
		{
			incomingBs.Read(swp.serverAddress);
			incomingBs.Read(swp.ping);

			unsigned int index2;
			for (index2=0; index2 < fw->targetServerPings.Size(); index2++)
			{
				if (fw->targetServerPings[index2].ping >= swp.ping )
					break;
			}
			fw->sourceServerPings.Insert(swp, index2, _FILE_AND_LINE_);
		}
	}

	// Both systems have to give us pings to progress here. Otherwise will timeout in Update()
	if (fw->sourceServerPings.Size()>0 &&
		fw->targetServerPings.Size()>0)
	{
		fw->OrderRemainingServersToTry();
		fw->timeRequestedPings=0;
		TryNextServer(fw->sata, fw);
	}
}
void UDPProxyCoordinator::TryNextServer(SenderAndTargetAddress sata, ForwardingRequest *fw)
{
	bool pickedGoodServer=false;
	while(fw->remainingServersToTry.Size()>0)
	{
		fw->currentlyAttemptedServerAddress=fw->remainingServersToTry.Pop();
		if (serverList.GetIndexOf(fw->currentlyAttemptedServerAddress)!=(unsigned int)-1)
		{
			pickedGoodServer=true;
			break;
		}
	}

	if (pickedGoodServer==false)
	{
		SendAllBusy(sata.senderClientAddress, sata.targetClientAddress, sata.targetClientGuid, fw->requestingAddress);
		forwardingRequestList.Remove(sata);
		RakNet::OP_DELETE(fw,_FILE_AND_LINE_);
		return;
	}

	SendForwardingRequest(sata.senderClientAddress, sata.targetClientAddress, fw->currentlyAttemptedServerAddress, fw->timeoutOnNoDataMS);
}
void UDPProxyCoordinator::SendAllBusy(SystemAddress senderClientAddress, SystemAddress targetClientAddress, RakNetGUID targetClientGuid, SystemAddress requestingAddress)
{
	RakNet::BitStream outgoingBs;
	outgoingBs.Write((MessageID)ID_UDP_PROXY_GENERAL);
	outgoingBs.Write((MessageID)ID_UDP_PROXY_ALL_SERVERS_BUSY);
	outgoingBs.Write(senderClientAddress);
	outgoingBs.Write(targetClientAddress);
	outgoingBs.Write(targetClientGuid);
	rakPeerInterface->Send(&outgoingBs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, requestingAddress, false);
}
void UDPProxyCoordinator::Clear(void)
{
	serverList.Clear(true, _FILE_AND_LINE_);
	for (unsigned int i=0; i < forwardingRequestList.Size(); i++)
	{
		RakNet::OP_DELETE(forwardingRequestList[i],_FILE_AND_LINE_);
	}
	forwardingRequestList.Clear(false, _FILE_AND_LINE_);
}
void UDPProxyCoordinator::ForwardingRequest::OrderRemainingServersToTry(void)
{
	//DataStructures::Multilist<ML_ORDERED_LIST,UDPProxyCoordinator::ServerWithPing,unsigned short> swpList;
	DataStructures::OrderedList<unsigned short, UDPProxyCoordinator::ServerWithPing, ServerWithPingComp> swpList;
	// swpList.SetSortOrder(true);

	if (sourceServerPings.Size()==0 && targetServerPings.Size()==0)
		return;

	unsigned int idx;
	UDPProxyCoordinator::ServerWithPing swp;
	for (idx=0; idx < remainingServersToTry.Size(); idx++)
	{
		swp.serverAddress=remainingServersToTry[idx];
		swp.ping=0;
		if (sourceServerPings.Size())
			swp.ping+=(unsigned short) (sourceServerPings[idx].ping);
		else
			swp.ping+=(unsigned short) (DEFAULT_CLIENT_UNRESPONSIVE_PING_TIME);
		if (targetServerPings.Size())
			swp.ping+=(unsigned short) (targetServerPings[idx].ping);
		else
			swp.ping+=(unsigned short) (DEFAULT_CLIENT_UNRESPONSIVE_PING_TIME);
		swpList.Insert(swp.ping, swp, false, _FILE_AND_LINE_);
	}
	remainingServersToTry.Clear(_FILE_AND_LINE_ );
	for (idx=0; idx < swpList.Size(); idx++)
	{
		remainingServersToTry.Push(swpList[idx].serverAddress, _FILE_AND_LINE_ );
	}
}

#endif // _RAKNET_SUPPORT_*
