mirror of
https://github.com/celisej567/mcpe.git
synced 2025-12-31 17:49:17 +03:00
439 lines
13 KiB
C++
439 lines
13 KiB
C++
/*
|
|
* Copyright (c) 2014, Oculus VR, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
*/
|
|
|
|
#include "NativeFeatureIncludes.h"
|
|
#if _RAKNET_SUPPORT_NatTypeDetectionServer==1
|
|
|
|
#include "NatTypeDetectionServer.h"
|
|
#include "SocketLayer.h"
|
|
#include "RakNetSmartPtr.h"
|
|
#include "SocketIncludes.h"
|
|
#include "RakPeerInterface.h"
|
|
#include "MessageIdentifiers.h"
|
|
#include "GetTime.h"
|
|
#include "BitStream.h"
|
|
#include "SocketDefines.h"
|
|
|
|
// #define NTDS_VERBOSE
|
|
|
|
using namespace RakNet;
|
|
|
|
STATIC_FACTORY_DEFINITIONS(NatTypeDetectionServer,NatTypeDetectionServer);
|
|
|
|
NatTypeDetectionServer::NatTypeDetectionServer()
|
|
{
|
|
s1p2=s2p3=s3p4=s4p5=0;
|
|
}
|
|
NatTypeDetectionServer::~NatTypeDetectionServer()
|
|
{
|
|
Shutdown();
|
|
}
|
|
void NatTypeDetectionServer::Startup(
|
|
const char *nonRakNetIP2,
|
|
const char *nonRakNetIP3,
|
|
const char *nonRakNetIP4
|
|
#ifdef __native_client__
|
|
,_PP_Instance_ chromeInstance
|
|
#endif
|
|
)
|
|
{
|
|
DataStructures::List<RakNetSocket2* > sockets;
|
|
rakPeerInterface->GetSockets(sockets);
|
|
char str[64];
|
|
sockets[0]->GetBoundAddress().ToString(false,str);
|
|
s1p2=
|
|
CreateNonblockingBoundSocket(str,
|
|
#ifdef __native_client__
|
|
chromeInstance,
|
|
#endif
|
|
this);
|
|
|
|
s2p3=
|
|
CreateNonblockingBoundSocket(nonRakNetIP2,
|
|
#ifdef __native_client__
|
|
chromeInstance,
|
|
#endif
|
|
this);
|
|
|
|
|
|
s3p4=
|
|
CreateNonblockingBoundSocket(nonRakNetIP3,
|
|
#ifdef __native_client__
|
|
chromeInstance,
|
|
#endif
|
|
this);
|
|
|
|
s4p5=
|
|
CreateNonblockingBoundSocket(nonRakNetIP4,
|
|
#ifdef __native_client__
|
|
chromeInstance,
|
|
#endif
|
|
this);
|
|
|
|
strcpy(s3p4Address, nonRakNetIP3);
|
|
|
|
|
|
#if !defined(__native_client__) && !defined(WINDOWS_STORE_RT)
|
|
if (s3p4->IsBerkleySocket())
|
|
((RNS2_Berkley*) s3p4)->CreateRecvPollingThread(0);
|
|
#endif
|
|
}
|
|
void NatTypeDetectionServer::Shutdown()
|
|
{
|
|
if (s1p2!=0)
|
|
{
|
|
RakNet::OP_DELETE(s1p2,_FILE_AND_LINE_);
|
|
s1p2=0;
|
|
}
|
|
if (s2p3!=0)
|
|
{
|
|
RakNet::OP_DELETE(s2p3,_FILE_AND_LINE_);
|
|
s2p3=0;
|
|
}
|
|
if (s3p4!=0)
|
|
{
|
|
#if !defined(__native_client__) && !defined(WINDOWS_STORE_RT)
|
|
if (s3p4->IsBerkleySocket())
|
|
((RNS2_Berkley *)s3p4)->BlockOnStopRecvPollingThread();
|
|
#endif
|
|
|
|
RakNet::OP_DELETE(s3p4,_FILE_AND_LINE_);
|
|
s3p4=0;
|
|
}
|
|
if (s4p5!=0)
|
|
{
|
|
RakNet::OP_DELETE(s4p5,_FILE_AND_LINE_);
|
|
s4p5=0;
|
|
}
|
|
bufferedPacketsMutex.Lock();
|
|
while (bufferedPackets.Size())
|
|
RakNet::OP_DELETE(bufferedPackets.Pop(), _FILE_AND_LINE_);
|
|
bufferedPacketsMutex.Unlock();
|
|
}
|
|
void NatTypeDetectionServer::Update(void)
|
|
{
|
|
int i=0;
|
|
RakNet::TimeMS time = RakNet::GetTimeMS();
|
|
RakNet::BitStream bs;
|
|
SystemAddress boundAddress;
|
|
|
|
RNS2RecvStruct *recvStruct;
|
|
bufferedPacketsMutex.Lock();
|
|
if (bufferedPackets.Size()>0)
|
|
recvStruct=bufferedPackets.Pop();
|
|
else
|
|
recvStruct=0;
|
|
bufferedPacketsMutex.Unlock();
|
|
while (recvStruct)
|
|
{
|
|
SystemAddress senderAddr = recvStruct->systemAddress;
|
|
char *data = recvStruct->data;
|
|
if (data[0]==NAT_TYPE_PORT_RESTRICTED && recvStruct->socket==s3p4)
|
|
{
|
|
RakNet::BitStream bsIn((unsigned char*) data,recvStruct->bytesRead,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)
|
|
{
|
|
|
|
#ifdef NTDS_VERBOSE
|
|
printf("Determined client is symmetric\n");
|
|
#endif
|
|
bs.Write((unsigned char) NAT_TYPE_SYMMETRIC);
|
|
}
|
|
else
|
|
{
|
|
// else port restricted
|
|
#ifdef NTDS_VERBOSE
|
|
|
|
printf("Determined client is port restricted\n");
|
|
#endif
|
|
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);
|
|
}
|
|
}
|
|
|
|
DeallocRNS2RecvStruct(recvStruct, _FILE_AND_LINE_);
|
|
bufferedPacketsMutex.Lock();
|
|
if (bufferedPackets.Size()>0)
|
|
recvStruct=bufferedPackets.Pop();
|
|
else
|
|
recvStruct=0;
|
|
bufferedPacketsMutex.Unlock();
|
|
}
|
|
|
|
/*
|
|
|
|
// 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)
|
|
{
|
|
|
|
#ifdef NTDS_VERBOSE
|
|
printf("Determined client is symmetric\n");
|
|
#endif
|
|
bs.Write((unsigned char) NAT_TYPE_SYMMETRIC);
|
|
}
|
|
else
|
|
{
|
|
// else port restricted
|
|
|
|
#ifdef NTDS_VERBOSE
|
|
printf("Determined client is port restricted\n");
|
|
#endif
|
|
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)
|
|
{
|
|
RNS2_SendParameters bsp;
|
|
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;
|
|
|
|
#ifdef NTDS_VERBOSE
|
|
printf("Testing NAT_TYPE_NONE\n");
|
|
#endif
|
|
// S4P5 sends to C2. If arrived, no NAT. Done. (Else S4P5 potentially banned, do not use again).
|
|
saOut=natDetectionAttempts[i].systemAddress;
|
|
saOut.SetPortHostOrder(natDetectionAttempts[i].c2Port);
|
|
// SocketLayer::SendTo_PC( s4p5, (const char*) &c, 1, saOut, __FILE__, __LINE__ );
|
|
bsp.data = (char*) &c;
|
|
bsp.length = 1;
|
|
bsp.systemAddress = saOut;
|
|
s4p5->Send(&bsp, _FILE_AND_LINE_);
|
|
break;
|
|
case STATE_TESTING_FULL_CONE_1:
|
|
case STATE_TESTING_FULL_CONE_2:
|
|
|
|
#ifdef NTDS_VERBOSE
|
|
printf("Testing NAT_TYPE_FULL_CONE\n");
|
|
#endif
|
|
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.SetPortHostOrder(natDetectionAttempts[i].systemAddress.GetPort());
|
|
// SocketLayer::SendTo_PC( s2p3, (const char*) bs.GetData(), bs.GetNumberOfBytesUsed(), saOut, __FILE__, __LINE__ );
|
|
bsp.data = (char*) bs.GetData();
|
|
bsp.length = bs.GetNumberOfBytesUsed();
|
|
bsp.systemAddress = saOut;
|
|
s2p3->Send(&bsp, _FILE_AND_LINE_);
|
|
break;
|
|
case STATE_TESTING_ADDRESS_RESTRICTED_1:
|
|
case STATE_TESTING_ADDRESS_RESTRICTED_2:
|
|
|
|
#ifdef NTDS_VERBOSE
|
|
printf("Testing NAT_TYPE_ADDRESS_RESTRICTED\n");
|
|
#endif
|
|
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.SetPortHostOrder(natDetectionAttempts[i].systemAddress.GetPort());
|
|
//SocketLayer::SendTo_PC( s1p2, (const char*) bs.GetData(), bs.GetNumberOfBytesUsed(), saOut, __FILE__, __LINE__ );
|
|
bsp.data = (char*) bs.GetData();
|
|
bsp.length = bs.GetNumberOfBytesUsed();
|
|
bsp.systemAddress = saOut;
|
|
s1p2->Send(&bsp, _FILE_AND_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
|
|
|
|
#ifdef NTDS_VERBOSE
|
|
printf("Testing NAT_TYPE_PORT_RESTRICTED\n");
|
|
#endif
|
|
bs.Write((unsigned char) ID_NAT_TYPE_DETECTION_REQUEST);
|
|
bs.Write(RakString::NonVariadic(s3p4Address));
|
|
bs.Write(s3p4->GetBoundAddress().GetPort());
|
|
rakPeerInterface->Send(&bs,HIGH_PRIORITY,RELIABLE,0,natDetectionAttempts[i].systemAddress,false);
|
|
break;
|
|
default:
|
|
|
|
#ifdef NTDS_VERBOSE
|
|
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");
|
|
#endif
|
|
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++;
|
|
}
|
|
}
|
|
PluginReceiveResult NatTypeDetectionServer::OnReceive(Packet *packet)
|
|
{
|
|
switch (packet->data[0])
|
|
{
|
|
case ID_NAT_TYPE_DETECTION_REQUEST:
|
|
OnDetectionRequest(packet);
|
|
return RR_STOP_PROCESSING_AND_DEALLOCATE;
|
|
}
|
|
return RR_CONTINUE_PROCESSING;
|
|
}
|
|
void NatTypeDetectionServer::OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
|
|
{
|
|
(void) lostConnectionReason;
|
|
(void) rakNetGUID;
|
|
|
|
unsigned int i = GetDetectionAttemptIndex(systemAddress);
|
|
if (i==(unsigned int)-1)
|
|
return;
|
|
natDetectionAttempts.RemoveAtIndexFast(i);
|
|
}
|
|
void NatTypeDetectionServer::OnDetectionRequest(Packet *packet)
|
|
{
|
|
unsigned int i = GetDetectionAttemptIndex(packet->systemAddress);
|
|
|
|
RakNet::BitStream bsIn(packet->data, packet->length, false);
|
|
bsIn.IgnoreBytes(1);
|
|
bool isRequest=false;
|
|
bsIn.Read(isRequest);
|
|
if (isRequest)
|
|
{
|
|
if (i!=(unsigned int)-1)
|
|
return; // Already in progress
|
|
|
|
NATDetectionAttempt nda;
|
|
nda.detectionState=STATE_NONE;
|
|
nda.systemAddress=packet->systemAddress;
|
|
nda.guid=packet->guid;
|
|
bsIn.Read(nda.c2Port);
|
|
nda.nextStateTime=0;
|
|
nda.timeBetweenAttempts=rakPeerInterface->GetLastPing(nda.systemAddress)*3+50;
|
|
natDetectionAttempts.Push(nda, _FILE_AND_LINE_);
|
|
}
|
|
else
|
|
{
|
|
if (i==(unsigned int)-1)
|
|
return; // Unknown
|
|
// They are done
|
|
natDetectionAttempts.RemoveAtIndexFast(i);
|
|
}
|
|
|
|
}
|
|
unsigned int NatTypeDetectionServer::GetDetectionAttemptIndex(const SystemAddress &sa)
|
|
{
|
|
for (unsigned int i=0; i < natDetectionAttempts.Size(); i++)
|
|
{
|
|
if (natDetectionAttempts[i].systemAddress==sa)
|
|
return i;
|
|
}
|
|
return (unsigned int) -1;
|
|
}
|
|
unsigned int NatTypeDetectionServer::GetDetectionAttemptIndex(RakNetGUID guid)
|
|
{
|
|
for (unsigned int i=0; i < natDetectionAttempts.Size(); i++)
|
|
{
|
|
if (natDetectionAttempts[i].guid==guid)
|
|
return i;
|
|
}
|
|
return (unsigned int) -1;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
void NatTypeDetectionServer::DeallocRNS2RecvStruct(RNS2RecvStruct *s, const char *file, unsigned int line)
|
|
{
|
|
RakNet::OP_DELETE(s, file, line);
|
|
}
|
|
// --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
RNS2RecvStruct *NatTypeDetectionServer::AllocRNS2RecvStruct(const char *file, unsigned int line)
|
|
{
|
|
return RakNet::OP_NEW<RNS2RecvStruct>(file,line);
|
|
}
|
|
|
|
void NatTypeDetectionServer::OnRNS2Recv(RNS2RecvStruct *recvStruct)
|
|
{
|
|
bufferedPacketsMutex.Lock();
|
|
bufferedPackets.Push(recvStruct,_FILE_AND_LINE_);
|
|
bufferedPacketsMutex.Unlock();
|
|
}
|
|
|
|
#endif // _RAKNET_SUPPORT_*
|