00001 #include "NativeFeatureIncludes.h"
00002 #if _RAKNET_SUPPORT_NatPunchthroughServer==1
00003
00004 #include "NatPunchthroughServer.h"
00005 #include "SocketLayer.h"
00006 #include "BitStream.h"
00007 #include "MessageIdentifiers.h"
00008 #include "RakPeerInterface.h"
00009 #include "MTUSize.h"
00010 #include "GetTime.h"
00011 #include "PacketLogger.h"
00012
00013 void NatPunchthroughServerDebugInterface_Printf::OnServerMessage(const char *msg)
00014 {
00015 printf("%s\n", msg);
00016 }
00017 #if _RAKNET_SUPPORT_PacketLogger==1
00018 void NatPunchthroughServerDebugInterface_PacketLogger::OnServerMessage(const char *msg)
00019 {
00020 if (pl)
00021 {
00022 pl->WriteMiscellaneous("Nat", msg);
00023 }
00024 }
00025 #endif
00026
00027 void NatPunchthroughServer::User::DeleteConnectionAttempt(NatPunchthroughServer::ConnectionAttempt *ca)
00028 {
00029 unsigned int index = connectionAttempts.GetIndexOf(ca);
00030 if ((unsigned int)index!=(unsigned int)-1)
00031 {
00032 RakNet::OP_DELETE(ca,__FILE__,__LINE__);
00033 connectionAttempts.RemoveAtIndex(index);
00034 }
00035 }
00036 void NatPunchthroughServer::User::DerefConnectionAttempt(NatPunchthroughServer::ConnectionAttempt *ca)
00037 {
00038 unsigned int index = connectionAttempts.GetIndexOf(ca);
00039 if ((unsigned int)index!=(unsigned int)-1)
00040 {
00041 connectionAttempts.RemoveAtIndex(index);
00042 }
00043 }
00044 bool NatPunchthroughServer::User::HasConnectionAttemptToUser(User *user)
00045 {
00046 unsigned int index;
00047 for (index=0; index < connectionAttempts.Size(); index++)
00048 {
00049 if (connectionAttempts[index]->recipient->guid==user->guid ||
00050 connectionAttempts[index]->sender->guid==user->guid)
00051 return true;
00052 }
00053 return false;
00054 }
00055 void NatPunchthroughServer::User::LogConnectionAttempts(RakNet::RakString &rs)
00056 {
00057 rs.Clear();
00058 unsigned int index;
00059 char guidStr[128], ipStr[128];
00060 guid.ToString(guidStr);
00061 systemAddress.ToString(true,ipStr);
00062 rs=RakNet::RakString("User systemAddress=%s guid=%s\n", ipStr, guidStr);
00063 rs+=RakNet::RakString("%i attempts in list:\n", connectionAttempts.Size());
00064 for (index=0; index < connectionAttempts.Size(); index++)
00065 {
00066 rs+=RakNet::RakString("%i. SessionID=%i ", index+1, connectionAttempts[index]->sessionId);
00067 if (connectionAttempts[index]->sender==this)
00068 rs+="(We are sender) ";
00069 else
00070 rs+="(We are recipient) ";
00071 if (isReady)
00072 rs+="(READY TO START) ";
00073 else
00074 rs+="(NOT READY TO START) ";
00075 if (connectionAttempts[index]->attemptPhase==NatPunchthroughServer::ConnectionAttempt::NAT_ATTEMPT_PHASE_NOT_STARTED)
00076 rs+="(NOT_STARTED). ";
00077 else
00078 rs+="(GETTING_RECENT_PORTS). ";
00079 if (connectionAttempts[index]->sender==this)
00080 {
00081 connectionAttempts[index]->recipient->guid.ToString(guidStr);
00082 connectionAttempts[index]->recipient->systemAddress.ToString(true,ipStr);
00083 }
00084 else
00085 {
00086 connectionAttempts[index]->sender->guid.ToString(guidStr);
00087 connectionAttempts[index]->sender->systemAddress.ToString(true,ipStr);
00088 }
00089
00090 rs+=RakNet::RakString("Target systemAddress=%s, guid=%s.\n", ipStr, guidStr);
00091 }
00092 }
00093
00094 int NatPunchthroughServer::NatPunchthroughUserComp( const RakNetGUID &key, User * const &data )
00095 {
00096 if (key < data->guid)
00097 return -1;
00098 if (key > data->guid)
00099 return 1;
00100 return 0;
00101 }
00102
00103 NatPunchthroughServer::NatPunchthroughServer()
00104 {
00105 lastUpdate=0;
00106 sessionId=0;
00107 natPunchthroughServerDebugInterface=0;
00108 }
00109 NatPunchthroughServer::~NatPunchthroughServer()
00110 {
00111 User *user, *otherUser;
00112 ConnectionAttempt *connectionAttempt;
00113 unsigned int j;
00114 while(users.Size())
00115 {
00116 user = users[0];
00117 for (j=0; j < user->connectionAttempts.Size(); j++)
00118 {
00119 connectionAttempt=user->connectionAttempts[j];
00120 if (connectionAttempt->sender==user)
00121 otherUser=connectionAttempt->recipient;
00122 else
00123 otherUser=connectionAttempt->sender;
00124 otherUser->DeleteConnectionAttempt(connectionAttempt);
00125 }
00126 RakNet::OP_DELETE(user,__FILE__,__LINE__);
00127 users[0]=users[users.Size()-1];
00128 users.RemoveAtIndex(users.Size()-1);
00129 }
00130 }
00131 void NatPunchthroughServer::SetDebugInterface(NatPunchthroughServerDebugInterface *i)
00132 {
00133 natPunchthroughServerDebugInterface=i;
00134 }
00135 void NatPunchthroughServer::Update(void)
00136 {
00137 ConnectionAttempt *connectionAttempt;
00138 User *user, *recipient;
00139 unsigned int i,j;
00140 RakNetTime time = RakNet::GetTime();
00141 if (time > lastUpdate+250)
00142 {
00143 lastUpdate=time;
00144
00145 for (i=0; i < users.Size(); i++)
00146 {
00147 user=users[i];
00148 for (j=0; j < user->connectionAttempts.Size(); j++)
00149 {
00150 connectionAttempt=user->connectionAttempts[j];
00151 if (connectionAttempt->sender==user)
00152 {
00153 if (connectionAttempt->attemptPhase!=ConnectionAttempt::NAT_ATTEMPT_PHASE_NOT_STARTED &&
00154 time > connectionAttempt->startTime &&
00155 time > 10000 + connectionAttempt->startTime )
00156 {
00157 RakNet::BitStream outgoingBs;
00158
00159
00160 outgoingBs.Write((MessageID)ID_NAT_TARGET_UNRESPONSIVE);
00161 outgoingBs.Write(connectionAttempt->recipient->guid);
00162 outgoingBs.Write(connectionAttempt->sessionId);
00163 rakPeerInterface->Send(&outgoingBs,HIGH_PRIORITY,RELIABLE_ORDERED,0,connectionAttempt->sender->systemAddress,false);
00164
00165
00166
00167
00168 outgoingBs.Reset();
00169 outgoingBs.Write((MessageID)ID_NAT_TARGET_UNRESPONSIVE);
00170 outgoingBs.Write(connectionAttempt->sender->guid);
00171 outgoingBs.Write(connectionAttempt->sessionId);
00172 rakPeerInterface->Send(&outgoingBs,HIGH_PRIORITY,RELIABLE_ORDERED,0,connectionAttempt->recipient->systemAddress,false);
00173
00174 connectionAttempt->sender->isReady=true;
00175 connectionAttempt->recipient->isReady=true;
00176 recipient=connectionAttempt->recipient;
00177
00178
00179 if (natPunchthroughServerDebugInterface)
00180 {
00181 char str[1024];
00182 char addr1[128], addr2[128];
00183
00184 connectionAttempt->sender->systemAddress.ToString(true,addr1);
00185 connectionAttempt->recipient->systemAddress.ToString(true,addr2);
00186 sprintf(str, "Sending ID_NAT_TARGET_UNRESPONSIVE to sender %s and recipient %s.", addr1, addr2);
00187 natPunchthroughServerDebugInterface->OnServerMessage(str);
00188 RakNet::RakString log;
00189 connectionAttempt->sender->LogConnectionAttempts(log);
00190 connectionAttempt->recipient->LogConnectionAttempts(log);
00191 }
00192
00193
00194 connectionAttempt->sender->DerefConnectionAttempt(connectionAttempt);
00195 connectionAttempt->recipient->DeleteConnectionAttempt(connectionAttempt);
00196
00197 StartPunchthroughForUser(user);
00198 StartPunchthroughForUser(recipient);
00199
00200 break;
00201 }
00202 }
00203 }
00204 }
00205 }
00206 }
00207 PluginReceiveResult NatPunchthroughServer::OnReceive(Packet *packet)
00208 {
00209 switch (packet->data[0])
00210 {
00211 case ID_NAT_PUNCHTHROUGH_REQUEST:
00212 OnNATPunchthroughRequest(packet);
00213 return RR_STOP_PROCESSING_AND_DEALLOCATE;
00214 case ID_NAT_GET_MOST_RECENT_PORT:
00215 OnGetMostRecentPort(packet);
00216 return RR_STOP_PROCESSING_AND_DEALLOCATE;
00217 case ID_NAT_CLIENT_READY:
00218 OnClientReady(packet);
00219 return RR_STOP_PROCESSING_AND_DEALLOCATE;
00220 }
00221 return RR_CONTINUE_PROCESSING;
00222 }
00223 void NatPunchthroughServer::OnClosedConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
00224 {
00225 (void) lostConnectionReason;
00226 (void) systemAddress;
00227
00228 unsigned int i=0;
00229 bool objectExists;
00230 i = users.GetIndexFromKey(rakNetGUID, &objectExists);
00231 if (objectExists)
00232 {
00233 RakNet::BitStream outgoingBs;
00234 DataStructures::List<User *> freedUpInProgressUsers;
00235 User *user = users[i];
00236 User *otherUser;
00237 unsigned int connectionAttemptIndex;
00238 ConnectionAttempt *connectionAttempt;
00239 for (connectionAttemptIndex=0; connectionAttemptIndex < user->connectionAttempts.Size(); connectionAttemptIndex++)
00240 {
00241 connectionAttempt=user->connectionAttempts[connectionAttemptIndex];
00242 outgoingBs.Reset();
00243 if (connectionAttempt->recipient==user)
00244 {
00245 otherUser=connectionAttempt->sender;
00246 }
00247 else
00248 {
00249 otherUser=connectionAttempt->recipient;
00250 }
00251
00252
00253
00254
00255 outgoingBs.Write((MessageID)ID_NAT_CONNECTION_TO_TARGET_LOST);
00256 outgoingBs.Write(rakNetGUID);
00257 outgoingBs.Write(connectionAttempt->sessionId);
00258 rakPeerInterface->Send(&outgoingBs,HIGH_PRIORITY,RELIABLE_ORDERED,0,otherUser->systemAddress,false);
00259
00260
00261 if (connectionAttempt->attemptPhase==ConnectionAttempt::NAT_ATTEMPT_PHASE_GETTING_RECENT_PORTS)
00262 {
00263 otherUser->isReady=true;
00264 freedUpInProgressUsers.Insert(otherUser, __FILE__, __LINE__ );
00265 }
00266
00267 otherUser->DeleteConnectionAttempt(connectionAttempt);
00268 }
00269
00270 RakNet::OP_DELETE(users[i], __FILE__, __LINE__);
00271 users.RemoveAtIndex(i);
00272
00273 for (i=0; i < freedUpInProgressUsers.Size(); i++)
00274 {
00275 StartPunchthroughForUser(freedUpInProgressUsers[i]);
00276 }
00277 }
00278 }
00279
00280 void NatPunchthroughServer::OnNewConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, bool isIncoming)
00281 {
00282 (void) systemAddress;
00283 (void) isIncoming;
00284
00285 User *user = RakNet::OP_NEW<User>(__FILE__,__LINE__);
00286 user->guid=rakNetGUID;
00287 user->mostRecentPort=0;
00288 user->systemAddress=systemAddress;
00289 user->isReady=true;
00290 users.Insert(rakNetGUID, user, true, __FILE__,__LINE__);
00291 }
00292 void NatPunchthroughServer::OnNATPunchthroughRequest(Packet *packet)
00293 {
00294 RakNet::BitStream outgoingBs;
00295 RakNet::BitStream incomingBs(packet->data, packet->length, false);
00296 incomingBs.IgnoreBytes(sizeof(MessageID));
00297 RakNetGUID recipientGuid, senderGuid;
00298 incomingBs.Read(recipientGuid);
00299 senderGuid=packet->guid;
00300 unsigned int i;
00301 bool objectExists;
00302 i = users.GetIndexFromKey(senderGuid, &objectExists);
00303 RakAssert(objectExists);
00304
00305 ConnectionAttempt *ca = RakNet::OP_NEW<ConnectionAttempt>(__FILE__,__LINE__);
00306 ca->sender=users[i];
00307 ca->sessionId=sessionId++;
00308 i = users.GetIndexFromKey(recipientGuid, &objectExists);
00309 if (objectExists==false)
00310 {
00311 outgoingBs.Write((MessageID)ID_NAT_TARGET_NOT_CONNECTED);
00312 outgoingBs.Write(recipientGuid);
00313 rakPeerInterface->Send(&outgoingBs,HIGH_PRIORITY,RELIABLE_ORDERED,0,packet->systemAddress,false);
00314 RakNet::OP_DELETE(ca,__FILE__,__LINE__);
00315 return;
00316 }
00317 ca->recipient=users[i];
00318 if (ca->recipient->HasConnectionAttemptToUser(ca->sender))
00319 {
00320 outgoingBs.Write((MessageID)ID_NAT_ALREADY_IN_PROGRESS);
00321 outgoingBs.Write(recipientGuid);
00322 rakPeerInterface->Send(&outgoingBs,HIGH_PRIORITY,RELIABLE_ORDERED,0,packet->systemAddress,false);
00323 RakNet::OP_DELETE(ca,__FILE__,__LINE__);
00324 return;
00325 }
00326
00327 ca->sender->connectionAttempts.Insert(ca, __FILE__, __LINE__ );
00328 ca->recipient->connectionAttempts.Insert(ca, __FILE__, __LINE__ );
00329
00330 StartPunchthroughForUser(ca->sender);
00331 }
00332 void NatPunchthroughServer::OnClientReady(Packet *packet)
00333 {
00334 unsigned int i;
00335 bool objectExists;
00336 i = users.GetIndexFromKey(packet->guid, &objectExists);
00337 if (objectExists)
00338 {
00339 users[i]->isReady=true;
00340 StartPunchthroughForUser(users[i]);
00341 }
00342 }
00343
00344 void NatPunchthroughServer::OnGetMostRecentPort(Packet *packet)
00345 {
00346 RakNet::BitStream bsIn(packet->data, packet->length, false);
00347 bsIn.IgnoreBytes(sizeof(MessageID));
00348 uint16_t sessionId;
00349 unsigned short mostRecentPort;
00350 bsIn.Read(sessionId);
00351 bsIn.Read(mostRecentPort);
00352
00353 unsigned int i,j;
00354 User *user;
00355 ConnectionAttempt *connectionAttempt;
00356 bool objectExists;
00357 i = users.GetIndexFromKey(packet->guid, &objectExists);
00358
00359 if (natPunchthroughServerDebugInterface)
00360 {
00361 RakNet::RakString log;
00362 char addr1[128], addr2[128];
00363 packet->systemAddress.ToString(true,addr1);
00364 packet->guid.ToString(addr2);
00365 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);
00366 natPunchthroughServerDebugInterface->OnServerMessage(log.C_String());
00367 }
00368
00369 if (objectExists)
00370 {
00371 user=users[i];
00372 user->mostRecentPort=mostRecentPort;
00373 RakNetTime time = RakNet::GetTime();
00374
00375 for (j=0; j < user->connectionAttempts.Size(); j++)
00376 {
00377 connectionAttempt=user->connectionAttempts[j];
00378 if (connectionAttempt->attemptPhase==ConnectionAttempt::NAT_ATTEMPT_PHASE_GETTING_RECENT_PORTS &&
00379 connectionAttempt->sender->mostRecentPort!=0 &&
00380 connectionAttempt->recipient->mostRecentPort!=0 &&
00381
00382 connectionAttempt->sessionId==sessionId)
00383 {
00384 SystemAddress senderSystemAddress = connectionAttempt->sender->systemAddress;
00385 SystemAddress recipientSystemAddress = connectionAttempt->recipient->systemAddress;
00386 SystemAddress recipientTargetAddress = recipientSystemAddress;
00387 SystemAddress senderTargetAddress = senderSystemAddress;
00388 recipientTargetAddress.port=connectionAttempt->recipient->mostRecentPort;
00389 senderTargetAddress.port=connectionAttempt->sender->mostRecentPort;
00390
00391
00392 int targetPing = rakPeerInterface->GetAveragePing(recipientTargetAddress);
00393 int senderPing = rakPeerInterface->GetAveragePing(senderSystemAddress);
00394 RakNetTime simultaneousAttemptTime;
00395 if (targetPing==-1 || senderPing==-1)
00396 simultaneousAttemptTime = time + 1500;
00397 else
00398 {
00399 int largerPing = targetPing > senderPing ? targetPing : senderPing;
00400 if (largerPing * 4 < 100)
00401 simultaneousAttemptTime = time + 100;
00402 else
00403 simultaneousAttemptTime = time + (largerPing * 4);
00404 }
00405
00406
00407 if (natPunchthroughServerDebugInterface)
00408 {
00409 RakNet::RakString log;
00410 char addr1[128], addr2[128];
00411 recipientSystemAddress.ToString(true,addr1);
00412 connectionAttempt->recipient->guid.ToString(addr2);
00413 log=RakNet::RakString("Sending ID_NAT_CONNECT_AT_TIME to recipient systemAddress %s guid %s", addr1, addr2);
00414 natPunchthroughServerDebugInterface->OnServerMessage(log.C_String());
00415 }
00416
00417
00418 RakNet::BitStream bsOut;
00419 bsOut.Write((MessageID)ID_TIMESTAMP);
00420 bsOut.Write(simultaneousAttemptTime);
00421 bsOut.Write((MessageID)ID_NAT_CONNECT_AT_TIME);
00422 bsOut.Write(connectionAttempt->sessionId);
00423 bsOut.Write(senderTargetAddress);
00424 for (j=0; j < MAXIMUM_NUMBER_OF_INTERNAL_IDS; j++)
00425 bsOut.Write(rakPeerInterface->GetInternalID(senderSystemAddress,j));
00426 bsOut.Write(connectionAttempt->sender->guid);
00427 bsOut.Write(false);
00428 rakPeerInterface->Send(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,recipientSystemAddress,false);
00429
00430
00431 if (natPunchthroughServerDebugInterface)
00432 {
00433 RakNet::RakString log;
00434 char addr1[128], addr2[128];
00435 senderSystemAddress.ToString(true,addr1);
00436 connectionAttempt->sender->guid.ToString(addr2);
00437 log=RakNet::RakString("Sending ID_NAT_CONNECT_AT_TIME to sender systemAddress %s guid %s", addr1, addr2);
00438 natPunchthroughServerDebugInterface->OnServerMessage(log.C_String());
00439 }
00440
00441
00442
00443 bsOut.Reset();
00444 bsOut.Write((MessageID)ID_TIMESTAMP);
00445 bsOut.Write(simultaneousAttemptTime);
00446 bsOut.Write((MessageID)ID_NAT_CONNECT_AT_TIME);
00447 bsOut.Write(connectionAttempt->sessionId);
00448 bsOut.Write(recipientTargetAddress);
00449 for (j=0; j < MAXIMUM_NUMBER_OF_INTERNAL_IDS; j++)
00450 bsOut.Write(rakPeerInterface->GetInternalID(recipientSystemAddress,j));
00451 bsOut.Write(connectionAttempt->recipient->guid);
00452 bsOut.Write(true);
00453 rakPeerInterface->Send(&bsOut,HIGH_PRIORITY,RELIABLE_ORDERED,0,senderSystemAddress,false);
00454
00455 connectionAttempt->recipient->DerefConnectionAttempt(connectionAttempt);
00456 connectionAttempt->sender->DeleteConnectionAttempt(connectionAttempt);
00457
00458
00459 return;
00460 }
00461 }
00462 }
00463 else
00464 {
00465
00466 if (natPunchthroughServerDebugInterface)
00467 {
00468 RakNet::RakString log;
00469 char addr1[128], addr2[128];
00470 packet->systemAddress.ToString(true,addr1);
00471 packet->guid.ToString(addr2);
00472 log=RakNet::RakString("Ignoring ID_NAT_GET_MOST_RECENT_PORT from systemAddress %s guid %s", addr1, addr2);
00473 natPunchthroughServerDebugInterface->OnServerMessage(log.C_String());
00474 }
00475
00476 }
00477 }
00478 void NatPunchthroughServer::StartPunchthroughForUser(User *user)
00479 {
00480 if (user->isReady==false)
00481 return;
00482
00483 ConnectionAttempt *connectionAttempt;
00484 User *sender,*recipient,*otherUser;
00485 unsigned int i;
00486 for (i=0; i < user->connectionAttempts.Size(); i++)
00487 {
00488 connectionAttempt=user->connectionAttempts[i];
00489 if (connectionAttempt->sender==user)
00490 {
00491 otherUser=connectionAttempt->recipient;
00492 sender=user;
00493 recipient=otherUser;
00494 }
00495 else
00496 {
00497 otherUser=connectionAttempt->sender;
00498 recipient=user;
00499 sender=otherUser;
00500 }
00501
00502 if (otherUser->isReady)
00503 {
00504 if (natPunchthroughServerDebugInterface)
00505 {
00506 char str[1024];
00507 char addr1[128], addr2[128];
00508 sender->systemAddress.ToString(true,addr1);
00509 recipient->systemAddress.ToString(true,addr2);
00510 sprintf(str, "Sending NAT_ATTEMPT_PHASE_GETTING_RECENT_PORTS to sender %s and recipient %s.", addr1, addr2);
00511 natPunchthroughServerDebugInterface->OnServerMessage(str);
00512 }
00513
00514 sender->isReady=false;
00515 recipient->isReady=false;
00516 connectionAttempt->attemptPhase=ConnectionAttempt::NAT_ATTEMPT_PHASE_GETTING_RECENT_PORTS;
00517 connectionAttempt->startTime=RakNet::GetTime();
00518
00519 sender->mostRecentPort=0;
00520 recipient->mostRecentPort=0;
00521
00522 RakNet::BitStream outgoingBs;
00523 outgoingBs.Write((MessageID)ID_NAT_GET_MOST_RECENT_PORT);
00524
00525 outgoingBs.Write(connectionAttempt->sessionId);
00526 rakPeerInterface->Send(&outgoingBs,HIGH_PRIORITY,RELIABLE_ORDERED,0,sender->systemAddress,false);
00527 rakPeerInterface->Send(&outgoingBs,HIGH_PRIORITY,RELIABLE_ORDERED,0,recipient->systemAddress,false);
00528
00529
00530 break;
00531 }
00532 }
00533 }
00534
00535 #endif // _RAKNET_SUPPORT_*