Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Port Forwarding for a networking newbie...

Discussion in 'Multiplayer' started by AndrewGrayGames, Jan 18, 2011.

  1. AndrewGrayGames

    AndrewGrayGames

    Joined:
    Nov 19, 2009
    Posts:
    3,821
    I've been working on the Networking for my FPS, Onslaught of the Laser Cat (In my signature.) I'm using a mildly modified version of the M2H networking code. While my tests do alright locally, I can't have other people connect, or connect to other people's games.

    I've been searching and ran across "port forwarding" as something I may need to set up. What exactly does this entail?
     
  2. PrimeDerektive

    PrimeDerektive

    Joined:
    Dec 13, 2009
    Posts:
    3,090
    Port forwarding is really easy, but setting it up is specific to your router make/model (although the process is usually very similar). You normally log in to your router's admin panel (usually something like 192.168.1.1 or 10.128.1.1 or something similar), then find the port forwarding section, pick the IP address of the machine that you want those ports forwarded on (the computer you'll be hosting the game on), and then pick the port range you want forwarded (if you used Leepo's tut, I think his default is 25001 or something).
     
  3. PrimeDerektive

    PrimeDerektive

    Joined:
    Dec 13, 2009
    Posts:
    3,090
    However, if your game relies on hosts having their ports forwarded, the multiplayer portion of it is probably going to fail miserably. I would try getting the masterserver NAT punchthrough to work (although I've never been able to do so myself). I did however have some luck playing with the PHP master server that someone posted in the showcase section.
     
  4. J_P_

    J_P_

    Joined:
    Jan 9, 2010
    Posts:
    1,027
    The PHP Masterserver is awesome but it won't help connecting to people behind a firewall -- currently I'm looking for a solution to this. Someone can start a server, successfully talk with the master server, but be behind a firewall and not let people connect.

    Is there a guide somewhere for using NAT punchthrough?
     
  5. AndrewGrayGames

    AndrewGrayGames

    Joined:
    Nov 19, 2009
    Posts:
    3,821
    I spent much of yesterday working with NAT punchthrough. The thing is, Unity 3 handles it vastly different than Unity 2.6. For instance, I had to knock out two cases in the old TestConnection() function and insert two new cases. This is my modified connection code:

    connection.js:
    Code (csharp):
    1. class netAddress
    2. {
    3.   var ipAddress : String = "";
    4.   var ipPort : int = 0;
    5. }
    6.  
    7. var address : netAddress;
    8.  
    9. var connectionInfo : String = "";
    10. var errorMessage : String = "";
    11.  
    12. public var hostData : HostData[];
    13. public var sortedList : Array;
    14. public var filterNATHosts : boolean = false;
    15.  
    16. private var timer : float = 0;
    17. private var lastRequest : float = 0;
    18. private var gameName : String = "";
    19.  
    20. private var nowConnecting : boolean = false;
    21. private var publicIP : boolean = false;
    22. private var probingPublicIP : boolean = false;
    23. private var useNAT : boolean = false;
    24.  
    25. private var natCapable : ConnectionTesterStatus = ConnectionTesterStatus.Undetermined;
    26. private var doneTestingNAT : boolean = false;
    27. private var testMessage : String = "NAT capabilities are being tested.";
    28.  
    29. private var ambassador : Ambassador;
    30.  
    31. // Awake executes before Start...
    32. function Awake() : void
    33. {
    34.   // Read the game's name from the Ambassador.
    35.   ambassador = FindObjectOfType( Ambassador );
    36.  
    37.   TestNATCapabilities();
    38.  
    39.   publicIP = Network.HavePublicAddress();
    40.   if( publicIP ) { Debug.Log( "Connection: This machine's IP is public." ); }
    41.   else { Debug.Log( "Connection: This machine's IP address is private." ); }
    42.  
    43.   NetworkPretest();
    44. }
    45.  
    46. function NetworkPretest()
    47. {
    48.   while( ! doneTestingNAT )
    49.   {
    50.     TestConnection();
    51.     yield;
    52.   }
    53. }
    54.  
    55. // Server engine hooks...
    56. function TestNATCapabilities()
    57. {
    58.   while( natCapable == ConnectionTesterStatus.Undetermined )
    59.   {
    60.     natCapable = Network.TestConnection();
    61.     yield;
    62.   }
    63.  
    64.   Debug.Log( "Am I capable of NAT punchthrough?  Answer: " + natCapable );
    65. }
    66.  
    67. function TestConnection() : void
    68. {
    69.   natCapable = Network.TestConnection();
    70.  
    71.   switch( natCapable )
    72.   {
    73.     case ConnectionTesterStatus.Error:
    74.       testMessage = "Problem determining NAT capabilities";
    75.       errorMessage = "Test complete.  Couldn't determine NAT punchthrough ability.";
    76.       doneTestingNAT = true;
    77.       break;
    78.            
    79.     case ConnectionTesterStatus.Undetermined:
    80.       testMessage = "Undetermined NAT capabilities";
    81.       errorMessage = "Testing connection...";
    82.       doneTestingNAT = false;
    83.       break;
    84.      
    85.     case ConnectionTesterStatus.NATpunchthroughFullCone:
    86.     case ConnectionTesterStatus.NATpunchthroughAddressRestrictedCone:
    87.       testMessage = "NAT can punchthrough as necessary.";
    88.       errorMessage = "";
    89.       doneTestingNAT = true;
    90.       useNAT = true;
    91.       break;
    92.      
    93.     case ConnectionTesterStatus.LimitedNATPunchthroughPortRestricted:
    94.         testMessage = "Everyone except Symmetric NATs can connect.";
    95.         errorMessage = "Test complete.  Some players cannot join your games.";
    96.         doneTestingNAT = true;
    97.         useNAT = true;
    98.         break;
    99.    
    100.     case ConnectionTesterStatus.LimitedNATPunchthroughSymmetric:
    101.         testMessage = "NAT Punchthrough is limited to asymmetric NAT systems.";
    102.         errorMessage = "Test complete.  Your NAT punchthrough is limited, do not host games.";
    103.         doneTestingNAT = true;
    104.         useNAT = true;
    105.         break;
    106.                    
    107.     case ConnectionTesterStatus.PublicIPIsConnectable:
    108.         testMessage = "Directly connectable public IP address.";
    109.         errorMessage = "";
    110.         doneTestingNAT = true;
    111.         useNAT = false;
    112.         break;
    113.        
    114.     // This case is a bit special as we now need to check if we can
    115.     // cicrumvent the blocking by using NAT punchthrough
    116.     case ConnectionTesterStatus.PublicIPPortBlocked:
    117.         testMessage = "Non-connectble public IP address (port " + address.ipPort + " blocked), running a server is impossible.";
    118.         errorMessage = "Test complete.  Port " + address.ipPort + " is blocked.  A server can't be started.";
    119.         useNAT = false;
    120.        
    121.         // If no NAT punchthrough test has been performed on this public IP, force a test
    122.         if ( !probingPublicIP )
    123.         {
    124.           Debug.Log("Testing if firewall can be circumnvented");
    125.           natCapable = Network.TestConnectionNAT();
    126.           probingPublicIP = true;
    127.           timer = Time.time + 10;
    128.         }
    129.         // NAT punchthrough test was performed but we still get blocked
    130.         else if( Time.time > timer )
    131.         {
    132.           probingPublicIP = false;      // reset
    133.           doneTestingNAT = true;
    134.           useNAT = true;
    135.         }
    136.         break;
    137.        
    138.     case ConnectionTesterStatus.PublicIPNoServerStarted:
    139.         testMessage = "Server not started, it is needed to check ability to connect with server. Restart the test when ready.";
    140.         break;
    141.    
    142.     default:
    143.         testMessage = "Error in test routine, got " + natCapable;
    144.         errorMessage = "Test complete.  There was an error in the connection test: " + natCapable;
    145.   }
    146.  
    147.   if( doneTestingNAT )
    148.   {
    149.     Debug.Log( "Connection: " + testMessage );
    150.     Debug.Log( "Connection: " + natCapable + " " + probingPublicIP + " " + doneTestingNAT );
    151.   }
    152.  
    153. }
    154. // End server engine hooks.
    155.  
    156. // Client engine hooks...
    157. function Connect( ipAddress : String, port : int ) : void
    158. {
    159.   address.ipAddress = ipAddress;
    160.   address.ipPort = port;
    161.  
    162.   Debug.Log( "Connection: Connecting to " + address.ipAddress + ":" + address.ipPort );
    163.   Network.Connect( address.ipAddress, address.ipPort );    
    164.   nowConnecting = true;
    165. }
    166.  
    167. function OnConnectedToServer() : void
    168. {
    169.   Network.isMessageQueueRunning = false;
    170.   address.ipAddress = Network.connections[0].ipAddress;
    171.   address.ipPort = Network.connections[0].port;
    172. }
    173.  
    174. function OnFailedToConnect() : void
    175. {
    176.   // Oh, S***.
    177.   errorMessage = "Couldn't connect to " + address.ipAddress + ":" + address.ipPort + ".";
    178. }
    179.  
    180. function OnFailedToConnectToMasterServer() : void
    181. {
    182.   // Oh, S***.
    183.   errorMessage = "Couldn't talk to the Master Server.";
    184. }
    185. // End client engine hooks.
    186.  
    187. // Functions the connection system needs to run.
    188. function HostGame( players : int, port : int, scene : int ) : void
    189. {
    190.   if( players < 1 ) { players = 1; }
    191.  
    192.   //var doNat : boolean = ! Network.HavePublicAddress();
    193.   var descData : String = scene + "";
    194.  
    195.   ambassador.gameDesc = descData;
    196.  
    197.   Network.InitializeServer( players,port,useNAT );
    198. }
    199.  
    200. function FindHosts()
    201. {
    202.   var timeout : int = 5;
    203.  
    204.   if( lastRequest == 0 || Time.realtimeSinceStartup > lastRequest + timeout )
    205.   {
    206.     lastRequest = Time.time;
    207.    
    208.     MasterServer.RequestHostList( ambassador.gameName );
    209.     yield WaitForSeconds( 1 );
    210.    
    211.     hostData = MasterServer.PollHostList();
    212.     yield WaitForSeconds( 1 );
    213.    
    214.     SortHostList();
    215.    
    216.     Debug.Log( "Host search complete.  Found " + sortedList.length + " games." );
    217.   }
    218. }
    219.  
    220. function SortHostList() : void
    221. {
    222.   var a : int;
    223.   var b : int;
    224.   var ctr : int = 0;
    225.   var subCtr : int = 0;
    226.   var baseList : HostData[] = hostData;
    227.  
    228.   sortedList = new Array();
    229.  
    230.   for( var data : HostData in baseList )
    231.   {
    232.     // Add the element to the list.
    233.     sortedList.Add( ctr );
    234.    
    235.     // Sort this newest element in the correct position based
    236.     // on numbers of connected players, unless the array is 0
    237.     // or 1 elements large.
    238.     if( sortedList.length <= 1 ) { break; }
    239.  
    240.     for( subCtr = sortedList.length - 1; ctr > 0; ctr-- )
    241.     {
    242.       a = hostData[sortedList[ ctr - 1]].connectedPlayers;
    243.       b = hostData[ctr].connectedPlayers;
    244.    
    245.       if( a < b ) { SwapElements( sortedList, ctr-1, ctr ); }
    246.       else { break; }
    247.     }
    248.    
    249.     ctr++;
    250.   }
    251. }
    252.  
    253. function SwapElements( array, a : int, b : int ) : void
    254. {
    255.   // This is a simple element swap.  Nothing showy.
    256.   var container = array[a];
    257.  
    258.   array[a] = array[b];
    259.   array[b] = container;
    260. }
    261. // End of connection system functions.
    I think that my trouble is happening - go figure - in the HostGame() function, even though I do the case-by-case check for punchthrough based on the results of the connection test.

    However, since I know now port forwarding won't solve this, I guess I can let this topic rest and try again elsewhere.
     
    Last edited: Jan 18, 2011