SystemAddress TCPInterface::Connect(const char* host, unsigned short remotePort, bool block, unsigned short socketFamily, const char *bindAddress) { if (threadRunning.GetValue()==0) return UNASSIGNED_SYSTEM_ADDRESS; int newRemoteClientIndex=-1; for (newRemoteClientIndex=0; newRemoteClientIndex < remoteClientsLength; newRemoteClientIndex++) { remoteClients[newRemoteClientIndex].isActiveMutex.Lock(); if (remoteClients[newRemoteClientIndex].isActive==false) { remoteClients[newRemoteClientIndex].SetActive(true); remoteClients[newRemoteClientIndex].isActiveMutex.Unlock(); break; } remoteClients[newRemoteClientIndex].isActiveMutex.Unlock(); } if (newRemoteClientIndex==-1) return UNASSIGNED_SYSTEM_ADDRESS; if (block) { SystemAddress systemAddress; systemAddress.FromString(host); systemAddress.SetPortHostOrder(remotePort); systemAddress.systemIndex=(SystemIndex) newRemoteClientIndex; char buffout[128]; systemAddress.ToString(false,buffout); __TCPSOCKET__ sockfd = SocketConnect(buffout, remotePort, socketFamily, bindAddress); // Windows RT TODO #if !defined(WINDOWS_STORE_RT) if (sockfd==0) #endif { remoteClients[newRemoteClientIndex].isActiveMutex.Lock(); remoteClients[newRemoteClientIndex].SetActive(false); remoteClients[newRemoteClientIndex].isActiveMutex.Unlock(); failedConnectionAttemptMutex.Lock(); failedConnectionAttempts.Push(systemAddress, _FILE_AND_LINE_ ); failedConnectionAttemptMutex.Unlock(); return UNASSIGNED_SYSTEM_ADDRESS; } remoteClients[newRemoteClientIndex].socket=sockfd; remoteClients[newRemoteClientIndex].systemAddress=systemAddress; completedConnectionAttemptMutex.Lock(); completedConnectionAttempts.Push(remoteClients[newRemoteClientIndex].systemAddress, _FILE_AND_LINE_ ); completedConnectionAttemptMutex.Unlock(); return remoteClients[newRemoteClientIndex].systemAddress; } else { ThisPtrPlusSysAddr *s = RakNet::OP_NEW<ThisPtrPlusSysAddr>( _FILE_AND_LINE_ ); s->systemAddress.FromStringExplicitPort(host,remotePort); s->systemAddress.systemIndex=(SystemIndex) newRemoteClientIndex; if (bindAddress) strcpy(s->bindAddress, bindAddress); else s->bindAddress[0]=0; s->tcpInterface=this; s->socketFamily=socketFamily; // Start the connection thread int errorCode; errorCode = RakNet::RakThread::Create(ConnectionAttemptLoop, s, threadPriority); if (errorCode!=0) { RakNet::OP_DELETE(s, _FILE_AND_LINE_); failedConnectionAttempts.Push(s->systemAddress, _FILE_AND_LINE_ ); } return UNASSIGNED_SYSTEM_ADDRESS; } }
void NatPunchthroughServer::OnGetMostRecentPort(Packet *packet) { RakNet::BitStream bsIn(packet->data, packet->length, false); bsIn.IgnoreBytes(sizeof(MessageID)); uint16_t sessionId; unsigned short mostRecentPort; bsIn.Read(sessionId); bsIn.Read(mostRecentPort); unsigned int i,j; User *user; ConnectionAttempt *connectionAttempt; bool objectExists; i = users.GetIndexFromKey(packet->guid, &objectExists); if (natPunchthroughServerDebugInterface) { RakNet::RakString log; char addr1[128], addr2[128]; packet->systemAddress.ToString(true,addr1); packet->guid.ToString(addr2); log=RakNet::RakString("Got ID_NAT_GET_MOST_RECENT_PORT from systemAddress %s guid %s. port=%i. sessionId=%i. userFound=%i.", addr1, addr2, mostRecentPort, sessionId, objectExists); natPunchthroughServerDebugInterface->OnServerMessage(log.C_String()); } if (objectExists) { user=users[i]; user->mostRecentPort=mostRecentPort; RakNet::Time time = RakNet::GetTime(); for (j=0; j < user->connectionAttempts.Size(); j++) { connectionAttempt=user->connectionAttempts[j]; if (connectionAttempt->attemptPhase==ConnectionAttempt::NAT_ATTEMPT_PHASE_GETTING_RECENT_PORTS && connectionAttempt->sender->mostRecentPort!=0 && connectionAttempt->recipient->mostRecentPort!=0 && // 04/29/08 add sessionId to prevent processing for other systems connectionAttempt->sessionId==sessionId) { SystemAddress senderSystemAddress = connectionAttempt->sender->systemAddress; SystemAddress recipientSystemAddress = connectionAttempt->recipient->systemAddress; SystemAddress recipientTargetAddress = recipientSystemAddress; SystemAddress senderTargetAddress = senderSystemAddress; recipientTargetAddress.SetPortHostOrder(connectionAttempt->recipient->mostRecentPort); senderTargetAddress.SetPortHostOrder(connectionAttempt->sender->mostRecentPort); // Pick a time far enough in the future that both systems will have gotten the message int targetPing = rakPeerInterface->GetAveragePing(recipientTargetAddress); int senderPing = rakPeerInterface->GetAveragePing(senderSystemAddress); RakNet::Time simultaneousAttemptTime; if (targetPing==-1 || senderPing==-1) simultaneousAttemptTime = time + 1500; else { int largerPing = targetPing > senderPing ? targetPing : senderPing; if (largerPing * 4 < 100) simultaneousAttemptTime = time + 100; else simultaneousAttemptTime = time + (largerPing * 4); } if (natPunchthroughServerDebugInterface) { RakNet::RakString log; char addr1[128], addr2[128]; recipientSystemAddress.ToString(true,addr1); connectionAttempt->recipient->guid.ToString(addr2); log=RakNet::RakString("Sending ID_NAT_CONNECT_AT_TIME to recipient systemAddress %s guid %s", addr1, addr2); natPunchthroughServerDebugInterface->OnServerMessage(log.C_String()); } // Send to recipient timestamped message to connect at time RakNet::BitStream bsOut; bsOut.Write((MessageID)ID_TIMESTAMP); bsOut.Write(simultaneousAttemptTime); bsOut.Write((MessageID)ID_NAT_CONNECT_AT_TIME); bsOut.Write(connectionAttempt->sessionId); bsOut.Write(senderTargetAddress); // Public IP, using most recent port for (j=0; j < MAXIMUM_NUMBER_OF_INTERNAL_IDS; j++) // Internal IP bsOut.Write(rakPeerInterface->GetInternalID(senderSystemAddress,j)); bsOut.Write(connectionAttempt->sender->guid); bsOut.Write(false); rakPeerInterface->Send(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,recipientSystemAddress,false); if (natPunchthroughServerDebugInterface) { RakNet::RakString log; char addr1[128], addr2[128]; senderSystemAddress.ToString(true,addr1); connectionAttempt->sender->guid.ToString(addr2); log=RakNet::RakString("Sending ID_NAT_CONNECT_AT_TIME to sender systemAddress %s guid %s", addr1, addr2); natPunchthroughServerDebugInterface->OnServerMessage(log.C_String()); } // Same for sender bsOut.Reset(); bsOut.Write((MessageID)ID_TIMESTAMP); bsOut.Write(simultaneousAttemptTime); bsOut.Write((MessageID)ID_NAT_CONNECT_AT_TIME); bsOut.Write(connectionAttempt->sessionId); bsOut.Write(recipientTargetAddress); // Public IP, using most recent port for (j=0; j < MAXIMUM_NUMBER_OF_INTERNAL_IDS; j++) // Internal IP bsOut.Write(rakPeerInterface->GetInternalID(recipientSystemAddress,j)); bsOut.Write(connectionAttempt->recipient->guid); bsOut.Write(true); rakPeerInterface->Send(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,senderSystemAddress,false); connectionAttempt->recipient->DerefConnectionAttempt(connectionAttempt); connectionAttempt->sender->DeleteConnectionAttempt(connectionAttempt); // 04/29/08 missing return return; } } } else { if (natPunchthroughServerDebugInterface) { RakNet::RakString log; char addr1[128], addr2[128]; packet->systemAddress.ToString(true,addr1); packet->guid.ToString(addr2); log=RakNet::RakString("Ignoring ID_NAT_GET_MOST_RECENT_PORT from systemAddress %s guid %s", addr1, addr2); natPunchthroughServerDebugInterface->OnServerMessage(log.C_String()); } } }
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++; } }