• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

NatPunchthroughClient.cpp

Go to the documentation of this file.
00001 #include "NativeFeatureIncludes.h"
00002 #if _RAKNET_SUPPORT_NatPunchthroughClient==1
00003 
00004 #include "NatPunchthroughClient.h"
00005 #include "BitStream.h"
00006 #include "MessageIdentifiers.h"
00007 #include "RakPeerInterface.h"
00008 #include "GetTime.h"
00009 #include "PacketLogger.h"
00010 
00011 void NatPunchthroughDebugInterface_Printf::OnClientMessage(const char *msg)
00012 {
00013         printf("%s\n", msg);
00014 }
00015 #if _RAKNET_SUPPORT_PacketLogger==1
00016 void NatPunchthroughDebugInterface_PacketLogger::OnClientMessage(const char *msg)
00017 {
00018         if (pl)
00019         {
00020                 pl->WriteMiscellaneous("Nat", msg);
00021         }
00022 }
00023 #endif
00024 
00025 NatPunchthroughClient::NatPunchthroughClient()
00026 {
00027         natPunchthroughDebugInterface=0;
00028         mostRecentNewExternalPort=0;
00029         sp.nextActionTime=0;
00030 }
00031 NatPunchthroughClient::~NatPunchthroughClient()
00032 {
00033         rakPeerInterface=0;
00034         Clear();
00035 }
00036 bool NatPunchthroughClient::OpenNAT(RakNetGUID destination, SystemAddress facilitator)
00037 {
00038         if (rakPeerInterface->IsConnected(facilitator)==false)
00039                 return false;
00040         // Already connected
00041         SystemAddress sa = rakPeerInterface->GetSystemAddressFromGuid(destination);
00042         if (sa!=UNASSIGNED_SYSTEM_ADDRESS && rakPeerInterface->IsConnected(sa,true,true) )
00043                 return false;
00044 
00045         SendPunchthrough(destination, facilitator);
00046         return true;
00047 }
00048 void NatPunchthroughClient::SetDebugInterface(NatPunchthroughDebugInterface *i)
00049 {
00050         natPunchthroughDebugInterface=i;
00051 }
00052 unsigned short NatPunchthroughClient::GetUPNPExternalPort(void) const
00053 {
00054         return mostRecentNewExternalPort;
00055 }
00056 unsigned short NatPunchthroughClient::GetUPNPInternalPort(void) const
00057 {
00058         return rakPeerInterface->GetInternalID(UNASSIGNED_SYSTEM_ADDRESS).port;
00059 }
00060 RakNet::RakString NatPunchthroughClient::GetUPNPInternalAddress(void) const
00061 {
00062         char dest[64];
00063         rakPeerInterface->GetInternalID(UNASSIGNED_SYSTEM_ADDRESS).ToString(false, dest);
00064         RakNet::RakString rs = dest;
00065         return rs;
00066 }
00067 void NatPunchthroughClient::Update(void)
00068 {
00069         RakNetTimeMS time = RakNet::GetTimeMS();
00070         if (sp.nextActionTime && sp.nextActionTime < time)
00071         {
00072                 RakNetTimeMS delta = time - sp.nextActionTime;
00073                 if (sp.testMode==SendPing::TESTING_INTERNAL_IPS)
00074                 {
00075                         SendOutOfBand(sp.internalIds[sp.attemptCount],ID_NAT_ESTABLISH_UNIDIRECTIONAL);
00076 
00077                         if (++sp.retryCount>=pc.UDP_SENDS_PER_PORT_INTERNAL)
00078                         {
00079                                 ++sp.attemptCount;
00080                                 sp.retryCount=0;
00081                         }
00082 
00083                         if (sp.attemptCount>=pc.MAXIMUM_NUMBER_OF_INTERNAL_IDS_TO_CHECK)
00084                         {
00085                                 sp.testMode=SendPing::WAITING_FOR_INTERNAL_IPS_RESPONSE;
00086                                 if (pc.INTERNAL_IP_WAIT_AFTER_ATTEMPTS>0)
00087                                 {
00088                                         sp.nextActionTime=time+pc.INTERNAL_IP_WAIT_AFTER_ATTEMPTS-delta;
00089                                 }
00090                                 else
00091                                 {
00092                                         sp.testMode=SendPing::TESTING_EXTERNAL_IPS_FROM_FACILITATOR_PORT;
00093                                         sp.attemptCount=0;
00094                                 }
00095                         }
00096                         else
00097                         {
00098                                 sp.nextActionTime=time+pc.TIME_BETWEEN_PUNCH_ATTEMPTS_INTERNAL-delta;
00099                         }
00100                 }
00101                 else if (sp.testMode==SendPing::WAITING_FOR_INTERNAL_IPS_RESPONSE)
00102                 {
00103                         sp.testMode=SendPing::TESTING_EXTERNAL_IPS_FROM_FACILITATOR_PORT;
00104                         sp.attemptCount=0;
00105                 }
00106 
00107                 if (sp.testMode==SendPing::TESTING_EXTERNAL_IPS_FROM_FACILITATOR_PORT)
00108                 {
00109                         SystemAddress sa;
00110                         sa=sp.targetAddress;
00111                         int port = sa.port+sp.attemptCount;
00112                         sa.port=(unsigned short) port;
00113                         SendOutOfBand(sa,ID_NAT_ESTABLISH_UNIDIRECTIONAL);
00114 
00115                         if (++sp.retryCount>=pc.UDP_SENDS_PER_PORT_EXTERNAL)
00116                         {
00117                                 ++sp.attemptCount;
00118                                 sp.retryCount=0;
00119                                 sp.nextActionTime=time+pc.EXTERNAL_IP_WAIT_BETWEEN_PORTS-delta;
00120                         }
00121                         else
00122                         {
00123                                 sp.nextActionTime=time+pc.TIME_BETWEEN_PUNCH_ATTEMPTS_EXTERNAL-delta;
00124                         }
00125 
00126                         if (sp.attemptCount>=pc.MAX_PREDICTIVE_PORT_RANGE)
00127                         {
00128                                 // From 1024 disabled, never helps as I've seen, but slows down the process by half
00129                                 //sp.testMode=SendPing::TESTING_EXTERNAL_IPS_FROM_1024;
00130                                 //sp.attemptCount=0;
00131                                 sp.testMode=SendPing::WAITING_AFTER_ALL_ATTEMPTS;
00132                                 sp.nextActionTime=time+pc.EXTERNAL_IP_WAIT_AFTER_ALL_ATTEMPTS-delta;
00133                         }
00134                 }
00135                 else if (sp.testMode==SendPing::TESTING_EXTERNAL_IPS_FROM_1024)
00136                 {
00137                         SystemAddress sa;
00138                         sa=sp.targetAddress;
00139                         int port = 1024+sp.attemptCount;
00140                         sa.port=(unsigned short) port;
00141                         SendOutOfBand(sa,ID_NAT_ESTABLISH_UNIDIRECTIONAL);
00142 
00143                         if (++sp.retryCount>=pc.UDP_SENDS_PER_PORT_EXTERNAL)
00144                         {
00145                                 ++sp.attemptCount;
00146                                 sp.retryCount=0;
00147                                 sp.nextActionTime=time+pc.EXTERNAL_IP_WAIT_BETWEEN_PORTS-delta;
00148                         }
00149                         else
00150                         {
00151                                 sp.nextActionTime=time+pc.TIME_BETWEEN_PUNCH_ATTEMPTS_EXTERNAL-delta;
00152                         }
00153 
00154                         if (sp.attemptCount>=pc.MAX_PREDICTIVE_PORT_RANGE)
00155                         {
00156                                 if (natPunchthroughDebugInterface)
00157                                 {
00158                                         char ipAddressString[32];
00159                                         sp.targetAddress.ToString(true, ipAddressString);
00160                                         char guidString[128];
00161                                         sp.targetGuid.ToString(guidString);
00162                                         natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Likely bidirectional punchthrough failure to guid %s, system address %s.", guidString, ipAddressString));
00163                                 }
00164 
00165                                 sp.testMode=SendPing::WAITING_AFTER_ALL_ATTEMPTS;
00166                                 sp.nextActionTime=time+pc.EXTERNAL_IP_WAIT_AFTER_ALL_ATTEMPTS-delta;
00167                         }
00168                 }
00169                 else if (sp.testMode==SendPing::WAITING_AFTER_ALL_ATTEMPTS)
00170                 {
00171                         // Failed. Tell the user
00172                         OnPunchthroughFailure();
00173                 }
00174 
00175                 if (sp.testMode==SendPing::PUNCHING_FIXED_PORT)
00176                 {
00177 //                      RakAssert(rakPeerInterface->IsConnected(sp.targetAddress,true,true)==false);
00178                         SendOutOfBand(sp.targetAddress,ID_NAT_ESTABLISH_BIDIRECTIONAL);
00179                         if (++sp.retryCount>=sp.punchingFixedPortAttempts)
00180                         {
00181                                 if (natPunchthroughDebugInterface)
00182                                 {
00183                                         char ipAddressString[32];
00184                                         sp.targetAddress.ToString(true, ipAddressString);
00185                                         char guidString[128];
00186                                         sp.targetGuid.ToString(guidString);
00187                                         natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Likely unidirectional punchthrough failure to guid %s, system address %s.", guidString, ipAddressString));
00188                                 }
00189 
00190                                 sp.testMode=SendPing::WAITING_AFTER_ALL_ATTEMPTS;
00191                                 sp.nextActionTime=time+pc.EXTERNAL_IP_WAIT_AFTER_ALL_ATTEMPTS-delta;
00192                         }
00193                         else
00194                         {
00195                                 if ((sp.retryCount%pc.UDP_SENDS_PER_PORT_EXTERNAL)==0)
00196                                         sp.nextActionTime=time+pc.EXTERNAL_IP_WAIT_BETWEEN_PORTS-delta;
00197                                 else
00198                                         sp.nextActionTime=time+pc.TIME_BETWEEN_PUNCH_ATTEMPTS_EXTERNAL-delta;
00199                         }
00200                 }
00201         }
00202 }
00203 void NatPunchthroughClient::PushFailure(void)
00204 {
00205         Packet *p = rakPeerInterface->AllocatePacket(sizeof(MessageID)+sizeof(unsigned char));
00206         p->data[0]=ID_NAT_PUNCHTHROUGH_FAILED;
00207         p->systemAddress=sp.targetAddress;
00208         p->systemAddress.systemIndex=(SystemIndex)-1;
00209         p->guid=sp.targetGuid;
00210         if (sp.weAreSender)
00211                 p->data[1]=1;
00212         else
00213                 p->data[1]=0;
00214         rakPeerInterface->PushBackPacket(p, true);
00215 }
00216 void NatPunchthroughClient::OnPunchthroughFailure(void)
00217 {
00218         if (pc.retryOnFailure==false)
00219         {
00220                 if (natPunchthroughDebugInterface)
00221                 {
00222                         char ipAddressString[32];
00223                         sp.targetAddress.ToString(true, ipAddressString);
00224                         char guidString[128];
00225                         sp.targetGuid.ToString(guidString);
00226                         natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Failed punchthrough once. Returning failure to guid %s, system address %s to user.", guidString, ipAddressString));
00227                 }
00228 
00229                 PushFailure();
00230                 OnReadyForNextPunchthrough();
00231                 return;
00232         }
00233 
00234         unsigned int i;
00235         for (i=0; i < failedAttemptList.Size(); i++)
00236         {
00237                 if (failedAttemptList[i].guid==sp.targetGuid)
00238                 {
00239                         if (natPunchthroughDebugInterface)
00240                         {
00241                                 char ipAddressString[32];
00242                                 sp.targetAddress.ToString(true, ipAddressString);
00243                                 char guidString[128];
00244                                 sp.targetGuid.ToString(guidString);
00245                                 natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Failed punchthrough twice. Returning failure to guid %s, system address %s to user.", guidString, ipAddressString));
00246                         }
00247 
00248                         // Failed a second time, so return failed to user
00249                         PushFailure();
00250 
00251                         OnReadyForNextPunchthrough();
00252 
00253                         failedAttemptList.RemoveAtIndexFast(i);
00254                         return;
00255                 }
00256         }
00257 
00258         if (rakPeerInterface->IsConnected(sp.facilitator)==false)
00259         {
00260                 if (natPunchthroughDebugInterface)
00261                 {
00262                         char ipAddressString[32];
00263                         sp.targetAddress.ToString(true, ipAddressString);
00264                         char guidString[128];
00265                         sp.targetGuid.ToString(guidString);
00266                         natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Not connected to facilitator, so cannot retry punchthrough after first failure. Returning failure onj guid %s, system address %s to user.", guidString, ipAddressString));
00267                 }
00268 
00269                 // Failed, and can't try again because no facilitator
00270                 PushFailure();
00271                 return;
00272         }
00273 
00274         if (natPunchthroughDebugInterface)
00275         {
00276                 char ipAddressString[32];
00277                 sp.targetAddress.ToString(true, ipAddressString);
00278                 char guidString[128];
00279                 sp.targetGuid.ToString(guidString);
00280                 natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("First punchthrough failure on guid %s, system address %s. Reattempting.", guidString, ipAddressString));
00281         }
00282 
00283         // Failed the first time. Add to the failure queue and try again
00284         AddrAndGuid aag;
00285         aag.addr=sp.targetAddress;
00286         aag.guid=sp.targetGuid;
00287         failedAttemptList.Push(aag, __FILE__, __LINE__);
00288 
00289         // Tell the server we are ready
00290         OnReadyForNextPunchthrough();
00291 
00292         // If we are the sender, try again, immediately if possible, else added to the queue on the faciltiator
00293         if (sp.weAreSender)
00294                 SendPunchthrough(sp.targetGuid, sp.facilitator);
00295 }
00296 PluginReceiveResult NatPunchthroughClient::OnReceive(Packet *packet)
00297 {
00298         switch (packet->data[0])
00299         {
00300         case ID_NAT_GET_MOST_RECENT_PORT:
00301                 {
00302                         OnGetMostRecentPort(packet);
00303                         return RR_STOP_PROCESSING_AND_DEALLOCATE;
00304                 }
00305         case ID_OUT_OF_BAND_INTERNAL:
00306                 if (packet->length>=2 &&
00307                         (packet->data[1]==ID_NAT_ESTABLISH_UNIDIRECTIONAL || packet->data[1]==ID_NAT_ESTABLISH_BIDIRECTIONAL) &&
00308                         sp.nextActionTime!=0)
00309                 {
00310                         RakNet::BitStream bs(packet->data,packet->length,false);
00311                         bs.IgnoreBytes(2);
00312                         uint16_t sessionId;
00313                         bs.Read(sessionId);
00314 //                      RakAssert(sessionId<100);
00315                         if (sessionId!=sp.sessionId)
00316                                 break;
00317 
00318                         char ipAddressString[32];
00319                         packet->systemAddress.ToString(true,ipAddressString);
00320                         if (packet->data[1]==ID_NAT_ESTABLISH_UNIDIRECTIONAL)
00321                         {
00322                                 if (natPunchthroughDebugInterface)
00323                                 {
00324                                         char guidString[128];
00325                                         sp.targetGuid.ToString(guidString);
00326                                         natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Received ID_NAT_ESTABLISH_UNIDIRECTIONAL from guid %s, system address %s.", guidString, ipAddressString));
00327                                 }
00328                                 if (sp.testMode!=SendPing::PUNCHING_FIXED_PORT)
00329                                 {
00330                                         sp.testMode=SendPing::PUNCHING_FIXED_PORT;
00331                                         sp.retryCount+=sp.attemptCount*pc.UDP_SENDS_PER_PORT_EXTERNAL;
00332                                         sp.targetAddress=packet->systemAddress;
00333 //                                      RakAssert(rakPeerInterface->IsConnected(sp.targetAddress,true,true)==false);
00334                                         // Keeps trying until the other side gives up too, in case it is unidirectional
00335                                         sp.punchingFixedPortAttempts=pc.UDP_SENDS_PER_PORT_EXTERNAL*pc.MAX_PREDICTIVE_PORT_RANGE;
00336                                 }
00337 
00338                                 SendOutOfBand(sp.targetAddress,ID_NAT_ESTABLISH_BIDIRECTIONAL);
00339                         }
00340                         else if (packet->data[1]==ID_NAT_ESTABLISH_BIDIRECTIONAL &&
00341                                 sp.targetGuid==packet->guid)
00342                         {
00343                                 // They send back our port
00344                                 bs.Read(mostRecentNewExternalPort);
00345 
00346                                 SendOutOfBand(packet->systemAddress,ID_NAT_ESTABLISH_BIDIRECTIONAL);
00347 
00348                                 // Tell the user about the success
00349                                 sp.targetAddress=packet->systemAddress;
00350                                 PushSuccess();
00351                                 OnReadyForNextPunchthrough();
00352 //                              RakAssert(rakPeerInterface->IsConnected(sp.targetAddress,true,true)==false);
00353                                 bool removedFromFailureQueue=RemoveFromFailureQueue();
00354 
00355                                 if (natPunchthroughDebugInterface)
00356                                 {
00357                                         char guidString[128];
00358                                         sp.targetGuid.ToString(guidString);
00359                                         if (removedFromFailureQueue)
00360                                                 natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough to guid %s, system address %s succeeded on 2nd attempt.", guidString, ipAddressString));
00361                                         else
00362                                                 natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough to guid %s, system address %s succeeded on 1st attempt.", guidString, ipAddressString));
00363                                 }
00364                         }
00365 
00366         //              mostRecentNewExternalPort=packet->systemAddress.port;
00367                 }
00368                 return RR_STOP_PROCESSING_AND_DEALLOCATE;
00369         case ID_NAT_ALREADY_IN_PROGRESS:
00370                 {
00371                         RakNet::BitStream incomingBs(packet->data, packet->length, false);
00372                         incomingBs.IgnoreBytes(sizeof(MessageID));
00373                         RakNetGUID targetGuid;
00374                         incomingBs.Read(targetGuid);
00375                         if (natPunchthroughDebugInterface)
00376                         {
00377                                 char guidString[128];
00378                                 targetGuid.ToString(guidString);
00379                                 natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough retry to guid %s failed due to ID_NAT_ALREADY_IN_PROGRESS. Returning failure.", guidString));
00380                         }
00381 
00382                 }
00383                 break;
00384         case ID_NAT_TARGET_NOT_CONNECTED:
00385         case ID_NAT_CONNECTION_TO_TARGET_LOST:
00386         case ID_NAT_TARGET_UNRESPONSIVE:
00387                 {
00388                         char *reason;
00389                         if (packet->data[0]==ID_NAT_TARGET_NOT_CONNECTED)
00390                                 reason="ID_NAT_TARGET_NOT_CONNECTED";
00391                         else if (packet->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST)
00392                                 reason="ID_NAT_CONNECTION_TO_TARGET_LOST";
00393                         else
00394                                 reason="ID_NAT_TARGET_UNRESPONSIVE";
00395 
00396                         RakNet::BitStream incomingBs(packet->data, packet->length, false);
00397                         incomingBs.IgnoreBytes(sizeof(MessageID));
00398 
00399                         RakNetGUID targetGuid;
00400                         incomingBs.Read(targetGuid);
00401                         if (packet->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST ||
00402                                 packet->data[0]==ID_NAT_TARGET_UNRESPONSIVE)
00403                         {
00404                                 uint16_t sessionId;
00405                                 incomingBs.Read(sessionId);
00406                                 if (sessionId!=sp.sessionId)
00407                                         break;
00408                         }
00409 
00410                         unsigned int i;
00411                         for (i=0; i < failedAttemptList.Size(); i++)
00412                         {
00413                                 if (failedAttemptList[i].guid==targetGuid)
00414                                 {
00415                                         if (natPunchthroughDebugInterface)
00416                                         {
00417                                                 char guidString[128];
00418                                                 targetGuid.ToString(guidString);
00419                                                 natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough retry to guid %s failed due to %s.", guidString, reason));
00420 
00421                                         }
00422 
00423                                         // If the retry target is not connected, or loses connection, or is not responsive, then previous failures cannot be retried.
00424 
00425                                         // Don't need to return failed, the other messages indicate failure anyway
00426                                         /*
00427                                         Packet *p = rakPeerInterface->AllocatePacket(sizeof(MessageID));
00428                                         p->data[0]=ID_NAT_PUNCHTHROUGH_FAILED;
00429                                         p->systemAddress=failedAttemptList[i].addr;
00430                                         p->systemAddress.systemIndex=(SystemIndex)-1;
00431                                         p->guid=failedAttemptList[i].guid;
00432                                         rakPeerInterface->PushBackPacket(p, false);
00433                                         */
00434 
00435                                         failedAttemptList.RemoveAtIndexFast(i);
00436                                         break;
00437                                 }
00438                         }
00439 
00440                         if (natPunchthroughDebugInterface)
00441                         {
00442                                 char guidString[128];
00443                                 targetGuid.ToString(guidString);
00444                                 natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Punchthrough attempt to guid %s failed due to %s.", guidString, reason));
00445                         }
00446 
00447                         // Stop trying punchthrough
00448                         sp.nextActionTime=0;
00449 
00450                         /*
00451                         RakNet::BitStream bs(packet->data, packet->length, false);
00452                         bs.IgnoreBytes(sizeof(MessageID));
00453                         RakNetGUID failedSystem;
00454                         bs.Read(failedSystem);
00455                         bool deletedFirst=false;
00456                         unsigned int i=0;
00457                         while (i < pendingOpenNAT.Size())
00458                         {
00459                                 if (pendingOpenNAT[i].destination==failedSystem)
00460                                 {
00461                                         if (i==0)
00462                                                 deletedFirst=true;
00463                                         pendingOpenNAT.RemoveAtIndex(i);
00464                                 }
00465                                 else
00466                                         i++;
00467                         }
00468                         // Failed while in progress. Go to next in attempt queue
00469                         if (deletedFirst && pendingOpenNAT.Size())
00470                         {
00471                                 SendPunchthrough(pendingOpenNAT[0].destination, pendingOpenNAT[0].facilitator);
00472                                 sp.nextActionTime=0;
00473                         }
00474                         */
00475                 }
00476                 break;
00477         case ID_TIMESTAMP:
00478                 if (packet->data[sizeof(MessageID)+sizeof(RakNetTime)]==ID_NAT_CONNECT_AT_TIME)
00479                 {
00480                         OnConnectAtTime(packet);
00481                         return RR_STOP_PROCESSING_AND_DEALLOCATE;
00482                 }
00483                 break;
00484         }
00485         return RR_CONTINUE_PROCESSING;
00486 }
00487 /*
00488 void NatPunchthroughClient::ProcessNextPunchthroughQueue(void)
00489 {
00490         // Go to the next attempt
00491         if (pendingOpenNAT.Size())
00492                 pendingOpenNAT.RemoveAtIndex(0);
00493 
00494         // Do next punchthrough attempt
00495         if (pendingOpenNAT.Size())
00496                 SendPunchthrough(pendingOpenNAT[0].destination, pendingOpenNAT[0].facilitator);
00497 
00498         sp.nextActionTime=0;
00499 }
00500 */
00501 void NatPunchthroughClient::OnConnectAtTime(Packet *packet)
00502 {
00503 //      RakAssert(sp.nextActionTime==0);
00504 
00505         RakNet::BitStream bs(packet->data, packet->length, false);
00506         bs.IgnoreBytes(sizeof(MessageID));
00507         bs.Read(sp.nextActionTime);
00508         bs.IgnoreBytes(sizeof(MessageID));
00509         bs.Read(sp.sessionId);
00510         bs.Read(sp.targetAddress);
00511         //RakAssert(rakPeerInterface->IsConnected(sp.targetAddress,true,true)==false);
00512         int j;
00513         for (j=0; j < MAXIMUM_NUMBER_OF_INTERNAL_IDS; j++)
00514                 bs.Read(sp.internalIds[j]);
00515         sp.attemptCount=0;
00516         sp.retryCount=0;
00517         if (pc.MAXIMUM_NUMBER_OF_INTERNAL_IDS_TO_CHECK>0)
00518         {
00519                 sp.testMode=SendPing::TESTING_INTERNAL_IPS;
00520         }
00521         else
00522         {
00523                 sp.testMode=SendPing::TESTING_EXTERNAL_IPS_FROM_FACILITATOR_PORT;
00524         }
00525         bs.Read(sp.targetGuid);
00526         bs.Read(sp.weAreSender);
00527 
00528         //RakAssert(rakPeerInterface->IsConnected(sp.targetAddress,true,true)==false);
00529 }
00530 void NatPunchthroughClient::SendTTL(SystemAddress sa)
00531 {
00532         if (sa==UNASSIGNED_SYSTEM_ADDRESS)
00533                 return;
00534         if (sa.port==0)
00535                 return;
00536 
00537         char ipAddressString[32];
00538         sa.ToString(false, ipAddressString);
00539         rakPeerInterface->SendTTL(ipAddressString,sa.port, 3);
00540 }
00541 void NatPunchthroughClient::SendOutOfBand(SystemAddress sa, MessageID oobId)
00542 {
00543         if (sa==UNASSIGNED_SYSTEM_ADDRESS)
00544                 return;
00545         if (sa.port==0)
00546                 return;
00547 
00548         //RakAssert(rakPeerInterface->IsConnected(sp.targetAddress,true,true)==false);
00549 
00550         RakNet::BitStream oob;
00551         oob.Write(oobId);
00552         oob.Write(sp.sessionId);
00553 //      RakAssert(sp.sessionId<100);
00554         if (oobId==ID_NAT_ESTABLISH_BIDIRECTIONAL)
00555                 oob.Write(sa.port);
00556         char ipAddressString[32];
00557         sa.ToString(false, ipAddressString);
00558         rakPeerInterface->SendOutOfBand((const char*) ipAddressString,sa.port,(const char*) oob.GetData(),oob.GetNumberOfBytesUsed());
00559 
00560         if (natPunchthroughDebugInterface)
00561         {
00562                 sa.ToString(true,ipAddressString);
00563                 char guidString[128];
00564                 sp.targetGuid.ToString(guidString);
00565 
00566                 if (oobId==ID_NAT_ESTABLISH_UNIDIRECTIONAL)
00567                         natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Sent OOB ID_NAT_ESTABLISH_UNIDIRECTIONAL to guid %s, system address %s.", guidString, ipAddressString));
00568                 else
00569                         natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Sent OOB ID_NAT_ESTABLISH_BIDIRECTIONAL to guid %s, system address %s.", guidString, ipAddressString));
00570         }
00571 }
00572 void NatPunchthroughClient::OnNewConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, bool isIncoming)
00573 {
00574         (void) rakNetGUID;
00575         (void) isIncoming;
00576 
00577         // Try to track new port mappings on the router. Not reliable, but better than nothing.
00578         SystemAddress ourExternalId = rakPeerInterface->GetExternalID(systemAddress);
00579         if (ourExternalId!=UNASSIGNED_SYSTEM_ADDRESS)
00580                 mostRecentNewExternalPort=ourExternalId.port;
00581 }
00582 
00583 void NatPunchthroughClient::OnClosedConnection(SystemAddress systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason )
00584 {
00585         (void) systemAddress;
00586         (void) rakNetGUID;
00587         (void) lostConnectionReason;
00588 
00589         if (sp.facilitator==systemAddress)
00590         {
00591                 // If we lose the connection to the facilitator, all previous failures not currently in progress are returned as such
00592                 unsigned int i=0;
00593                 while (i < failedAttemptList.Size())
00594                 {
00595                         if (sp.nextActionTime!=0 && sp.targetGuid==failedAttemptList[i].guid)
00596                         {
00597                                 i++;
00598                                 continue;
00599                         }
00600 
00601                         PushFailure();
00602 
00603                         failedAttemptList.RemoveAtIndexFast(i);
00604                 }
00605         }
00606 
00607         /*
00608         (void) lostConnectionReason;
00609 
00610         bool deletedFirst=false;
00611         unsigned int i=0;
00612         while (i < pendingOpenNAT.Size())
00613         {
00614                 if (pendingOpenNAT[i].facilitator==systemAddress)
00615                 {
00616                         if (natPunchthroughDebugInterface)
00617                         {
00618                                 if (lostConnectionReason==LCR_CLOSED_BY_USER)
00619                                         natPunchthroughDebugInterface->OnClientMessage("Nat server connection lost. Reason=LCR_CLOSED_BY_USER\n");
00620                                 else if (lostConnectionReason==LCR_DISCONNECTION_NOTIFICATION)
00621                                         natPunchthroughDebugInterface->OnClientMessage("Nat server connection lost. Reason=LCR_CLOSED_BY_USER\n");
00622                                 else if (lostConnectionReason==LCR_CONNECTION_LOST)
00623                                         natPunchthroughDebugInterface->OnClientMessage("Nat server connection lost. Reason=LCR_CONNECTION_LOST\n");
00624                         }
00625 
00626                         // Request failed because connection to server lost before remote system ping attempt occurred
00627                         Packet *p = rakPeerInterface->AllocatePacket(sizeof(MessageID));
00628                         p->data[0]=ID_NAT_CONNECTION_TO_TARGET_LOST;
00629                         p->systemAddress=systemAddress;
00630                         p->systemAddress.systemIndex=(SystemIndex)-1;
00631                         p->guid=rakNetGUID;
00632                         rakPeerInterface->PushBackPacket(p, false);
00633                         if (i==0)
00634                                 deletedFirst;
00635 
00636                         pendingOpenNAT.RemoveAtIndex(i);
00637                 }
00638                 else
00639                         i++;
00640         }
00641 
00642         // Lost connection to facilitator while an attempt was in progress. Give up on that attempt, and try the next in the queue.
00643         if (deletedFirst && pendingOpenNAT.Size())
00644         {
00645                 SendPunchthrough(pendingOpenNAT[0].destination, pendingOpenNAT[0].facilitator);
00646         }
00647         */
00648 }
00649 void NatPunchthroughClient::OnGetMostRecentPort(Packet *packet)
00650 {
00651         RakNet::BitStream incomingBs(packet->data,packet->length,false);
00652         incomingBs.IgnoreBytes(sizeof(MessageID));
00653         uint16_t sessionId;
00654         incomingBs.Read(sessionId);
00655 
00656         RakNet::BitStream outgoingBs;
00657         outgoingBs.Write((MessageID)ID_NAT_GET_MOST_RECENT_PORT);
00658         outgoingBs.Write(sessionId);
00659         outgoingBs.Write(mostRecentNewExternalPort);
00660         rakPeerInterface->Send(&outgoingBs,HIGH_PRIORITY,RELIABLE_ORDERED,0,packet->systemAddress,false);
00661         sp.facilitator=packet->systemAddress;
00662 }
00663 /*
00664 unsigned int NatPunchthroughClient::GetPendingOpenNATIndex(RakNetGUID destination, SystemAddress facilitator)
00665 {
00666         unsigned int i;
00667         for (i=0; i < pendingOpenNAT.Size(); i++)
00668         {
00669                 if (pendingOpenNAT[i].destination==destination && pendingOpenNAT[i].facilitator==facilitator)
00670                         return i;
00671         }
00672         return (unsigned int) -1;
00673 }
00674 */
00675 void NatPunchthroughClient::SendPunchthrough(RakNetGUID destination, SystemAddress facilitator)
00676 {
00677         RakNet::BitStream outgoingBs;
00678         outgoingBs.Write((MessageID)ID_NAT_PUNCHTHROUGH_REQUEST);
00679         outgoingBs.Write(destination);
00680         rakPeerInterface->Send(&outgoingBs,HIGH_PRIORITY,RELIABLE_ORDERED,0,facilitator,false);
00681 
00682 //      RakAssert(rakPeerInterface->GetSystemAddressFromGuid(destination)==UNASSIGNED_SYSTEM_ADDRESS);
00683 
00684         if (natPunchthroughDebugInterface)
00685         {
00686                 char guidString[128];
00687                 destination.ToString(guidString);
00688                 natPunchthroughDebugInterface->OnClientMessage(RakNet::RakString("Starting ID_NAT_PUNCHTHROUGH_REQUEST to guid %s.", guidString));
00689         }
00690 }
00691 void NatPunchthroughClient::OnAttach(void)
00692 {
00693         Clear();
00694 }
00695 void NatPunchthroughClient::OnDetach(void)
00696 {
00697         Clear();
00698 }
00699 void NatPunchthroughClient::OnRakPeerShutdown(void)
00700 {
00701         Clear();
00702 }
00703 void NatPunchthroughClient::Clear(void)
00704 {
00705         OnReadyForNextPunchthrough();
00706 
00707         failedAttemptList.Clear(false, __FILE__,__LINE__);
00708 }
00709 PunchthroughConfiguration* NatPunchthroughClient::GetPunchthroughConfiguration(void)
00710 {
00711         return &pc;
00712 }
00713 void NatPunchthroughClient::OnReadyForNextPunchthrough(void)
00714 {
00715         if (rakPeerInterface==0)
00716                 return;
00717 
00718         sp.nextActionTime=0;
00719 
00720         RakNet::BitStream outgoingBs;
00721         outgoingBs.Write((MessageID)ID_NAT_CLIENT_READY);
00722         rakPeerInterface->Send(&outgoingBs,HIGH_PRIORITY,RELIABLE_ORDERED,0,sp.facilitator,false);
00723 }
00724 
00725 void NatPunchthroughClient::PushSuccess(void)
00726 {
00727 //      RakAssert(rakPeerInterface->IsConnected(sp.targetAddress,true,true)==false);
00728 
00729         Packet *p = rakPeerInterface->AllocatePacket(sizeof(MessageID)+sizeof(unsigned char));
00730         p->data[0]=ID_NAT_PUNCHTHROUGH_SUCCEEDED;
00731         p->systemAddress=sp.targetAddress;
00732         p->systemAddress.systemIndex=(SystemIndex)-1;
00733         p->guid=sp.targetGuid;
00734         if (sp.weAreSender)
00735                 p->data[1]=1;
00736         else
00737                 p->data[1]=0;
00738         rakPeerInterface->PushBackPacket(p, true);
00739 }
00740 
00741 bool NatPunchthroughClient::RemoveFromFailureQueue(void)
00742 {
00743         unsigned int i;
00744         for (i=0; i < failedAttemptList.Size(); i++)
00745         {
00746                 if (failedAttemptList[i].guid==sp.targetGuid)
00747                 {
00748                         // Remove from failure queue
00749                         failedAttemptList.RemoveAtIndexFast(i);
00750                         return true;
00751                 }
00752         }
00753         return false;
00754 }
00755 
00756 #endif // _RAKNET_SUPPORT_*
00757 

Generated on Thu Sep 30 2010 01:27:25 for RakNet by  doxygen 1.7.1