Files
minecraft-pe-0.6.1/src/raknet/UDPProxyCoordinator.cpp
2026-03-02 22:04:18 +03:00

544 lines
20 KiB
C++
Executable File

#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_*