Author Topic: Setting up a local server instance and connecting returns "Invalid Arguments"  (Read 6818 times)

andrew

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 44
    • View Profile
First, I have to say TNet is awesome.  Very easy to understand, well written just like NGUI, and fun to use :)

I have a problem though ( there's a workaround, but i'm afraid something isn't right in my code ).  So I have a scene with an object and my custom NetManager script ( included below ).  It basically will auto start a local server if I need it to, and will auto connect to that server (or any server available).  I used ExampleMenu.cs and TNAutoJoin.cs as references.

It works, but when I auto start a local server and connect with TNManager.Connect( ent.externalAddress, ent.internalAddress ) from the TNUdpLobbyClient server list, I get returned "Invalid Arguments".   The address in ent.internalAddress isn't my local ip address.  It's close, but it's not the IP address of my mac.  For example it's 10.211.5.2 and I'm using an Airport Extreme which gives me 10.0.1.6.  My external IP address is correct.

If I however use TNManager.Connect( ent.internalAddress.ToString() ) when I auto start the local server.  It works fine.

I've attached a screenshot of the object my code and TNManager are added to.

My NetManager prototyping code is here (in case anyone finds it of use):

  1. using UnityEngine;
  2. using System.Collections;
  3. using TNet;
  4.  
  5. /*
  6. -----------------------
  7.  
  8.  NetManager
  9.  handles connecting to an existing server or creating a new one
  10.  
  11. -----------------------
  12. */
  13. public class NetManager : MonoBehaviour {
  14.        
  15.         public string           serverAddress = "127.0.0.1";
  16.         public int                      serverTcpPort = 5127;
  17.         public string           remoteServerAddress = "127.0.0.1";
  18.         public int                      channelID = 1;
  19.         public bool                     autoStartLocalServer = false;
  20.         public bool                     autoConnect = true;
  21.        
  22.         private string          successFunctionName = string.Empty;
  23.         private string          failureFunctionName = string.Empty;
  24.         private string          gameStateFileName = "server.dat";
  25.         private float           nextConnectTime = 0f;
  26.        
  27.         /*
  28.         -----------------------
  29.         Start()
  30.         -----------------------
  31.         */
  32.         void Start() {
  33.                
  34.                 // Make it possible to use UDP using a random port
  35.                 TNManager.StartUDP( Random.Range( 10000, 50000 ) );
  36.                
  37.                 // automatically start a local server
  38.                 if ( autoStartLocalServer ) {
  39.                         int udpPort = Random.Range( 10000, 40000 );
  40.  
  41.                         // Start a local server, loading the saved data if possible
  42.                         // The UDP port of the server doesn't matter much as it's optional,
  43.                         // and the clients get notified of it via Packet.ResponseSetUDP.
  44.                         TNUdpLobbyClient lan = GetComponent<TNUdpLobbyClient>();
  45.                         int lobbyPort = ( lan != null ) ? lan.remotePort : 0;
  46.                         TNServerInstance.Start( serverTcpPort, udpPort, gameStateFileName, lobbyPort );
  47.                         Debug.LogWarning( "Server auto-started..." );
  48.                 }
  49.                
  50.         }
  51.  
  52.         /*
  53.         -----------------------
  54.         OnDestroy()
  55.         -----------------------
  56.         */
  57.         void OnDestroy() {
  58.                 TNManager.Disconnect();
  59.                 // Stop the server, saving all the data
  60.                 if ( TNServerInstance.isActive ) {
  61.                         TNServerInstance.Stop( gameStateFileName );
  62.                 }
  63.         }
  64.        
  65.         /*
  66.         -----------------------
  67.         Update()
  68.         -----------------------
  69.         */
  70.         void Update() {
  71.                 // connect to any available server             
  72.                 if ( autoConnect && !TNManager.isConnected && ( Time.time > nextConnectTime ) ) {
  73.                         // List of discovered servers
  74.                         List<ServerList.Entry> list = TNLobbyClient.knownServers.list;
  75.  
  76.                         // Server list automatically collects servers that have recently announced themselves
  77.                         bool connecting = false;
  78.                         for ( int i = 0; i < list.Count; ++i ) {
  79.                                 ServerList.Entry ent = list[i];
  80. //                              if ( autoStartLocalServer ) {
  81. //                                      TNManager.Connect( ent.internalAddress.ToString() );
  82. //                                      Debug.LogWarning( "Connecting to " + ent.internalAddress.ToString() + "..." );
  83. //                              } else {
  84. //                                      TNManager.Connect( ent.externalAddress.ToString() );
  85. //                                      Debug.LogWarning( "Connecting to " + ent.externalAddress.ToString() + "..." );
  86. //                              }
  87.                                 TNManager.Connect( ent.externalAddress, ent.internalAddress );   // <<< returns "Invalid Arguments"
  88.                                 Debug.LogWarning( "Connecting to " + ent.externalAddress.ToString() + " | " + ent.internalAddress.ToString() );
  89.                                 connecting = true;
  90.                                 break;
  91.                         }
  92.                         if ( !connecting ) {
  93.                                 Debug.Log( "No servers found..." );
  94.                         }
  95.                         nextConnectTime = Time.time + ( (connecting) ? 10.0f : 1.0f );
  96.                 }
  97.         }
  98.        
  99.         /*
  100.         -----------------------
  101.         OnNetworkConnect()
  102.         on success, join a channel
  103.         -----------------------
  104.         */
  105.         void OnNetworkConnect( bool result, string message ) {
  106.                 if ( result ) {
  107.                         Debug.LogWarning( "Connected > Joining channel." );
  108.                         TNManager.JoinChannel( channelID, "" );
  109.                 } else if ( !string.IsNullOrEmpty( failureFunctionName ) ) {
  110.                         UnityTools.Broadcast( failureFunctionName, message );
  111.                         autoConnect = false;
  112.                 } else {
  113.                         Debug.LogError( message );     
  114.                         autoConnect = false;
  115.                 }
  116.         }
  117.  
  118.         /*
  119.         -----------------------
  120.         OnNetworkDisconnect()
  121.         go back to the main menu
  122.         -----------------------
  123.         */
  124.         void OnNetworkDisconnect() {
  125.                 Debug.LogError( "Disconnected..." );
  126.         }
  127.  
  128.         /*
  129.         -----------------------
  130.         OnNetworkJoinChannel()
  131.         joined a channel ( or failed trying )
  132.         -----------------------
  133.         */
  134.         void OnNetworkJoinChannel( bool result, string message ) {
  135.                 if ( result ) {
  136.                         if ( !string.IsNullOrEmpty( successFunctionName ) ) {
  137.                                 UnityTools.Broadcast( successFunctionName );
  138.                         }
  139.                         Debug.LogWarning( "Joined channel!" );
  140.                 } else {
  141.                         if ( !string.IsNullOrEmpty( failureFunctionName ) ) {
  142.                                 UnityTools.Broadcast( failureFunctionName, message );
  143.                         } else {
  144.                                 Debug.LogError( message );     
  145.                         }
  146.                         TNManager.Disconnect();
  147.                 }
  148.         }      
  149. }
  150.  
  151.  

Thanks...

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
There was a similar post about this 2-3 days ago. Try replacing the localAddress function with this one:
  1.         static public IPAddress localAddress
  2.         {
  3.                 get
  4.                 {
  5.                         if (mLocalAddress == null)
  6.                         {
  7.                                 try
  8.                                 {
  9.                                         IPHostEntry ent = Dns.GetHostEntry(Dns.GetHostName());
  10.  
  11.                                         foreach (IPAddress ip in ent.AddressList)
  12.                                         {
  13.                                                 if (IsValidAddress(ip))
  14.                                                 {
  15.                                                         mLocalAddress = ip;
  16.                                                         break;
  17.                                                 }
  18.                                         }
  19.                                 }
  20. #if DEBUG
  21.                                 catch (System.Exception ex)
  22.                                 {
  23.                                         System.Console.WriteLine("TNTools.LocalAddress: " + ex.Message);
  24. #else
  25.                                 catch (System.Exception)
  26.                                 {
  27. #endif
  28.                                         mLocalAddress = IPAddress.Loopback;
  29.                                 }
  30.                         }
  31.                         return mLocalAddress;
  32.                 }
  33.         }

andrew

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 44
    • View Profile
More info...

As you know, the above code fix didn't solve this problem for me.  Any virtual adapters whether they are from a VM or VPN can cause multiple local ip addresses to show up.  I don't think this will be limited to just developer machines.  I finally found a fix for this issue by extending IsValidAddress().  I have no idea if this will work on all virtual adapters (searching by name).  Scouring the internet on this topic, there is *no* reliable way of determining if a local ip address is from a virtual adapter or not.

Here's my "fix"

  1.         static public bool IsValidAddress (IPAddress address)
  2.         {
  3.                 if (address.AddressFamily != AddressFamily.InterNetwork) return false;
  4.                 if (address.Equals(IPAddress.Loopback)) return false;
  5.                 if (address.Equals(IPAddress.None)) return false;
  6.                 if (address.Equals(IPAddress.Any)) return false;
  7.                 // finally check for a virtual address used by a VM or VPN                             
  8.                 NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
  9.                 foreach (NetworkInterface nic in nics)
  10.                 {
  11.                         IPInterfaceProperties ipProps = nic.GetIPProperties();
  12.                         foreach (UnicastIPAddressInformation ip in ipProps.UnicastAddresses)
  13.                         {
  14.                                 if ( ip.Address.Equals( address ) && (nic.Description.IndexOf("vnic", System.StringComparison.OrdinalIgnoreCase) >= 0) ) return false;
  15.                         }                
  16.                 }              
  17.                 return true;
  18.         }
  19.  

So now it returns my actual local ip address, however, I'm still getting "Invalid Arguments" when I used the Connect() method that passes in both external and internal ip addresses.  I get that error message from this code block in TNGameClient

  1.         case Packet.Error:
  2.         {
  3.                 if (mTcp.stage != TcpProtocol.Stage.Connected && onConnect != null)
  4.                 {
  5.                         [color=red]onConnect(false, reader.ReadString());[/color]
  6.                 }
  7.                 else if (onError != null)
  8.                 {
  9.                         onError(reader.ReadString());
  10.                 }
  11.                 break;
  12.         }
  13.  
  14.  

Callstack:

Invalid arguments
UnityEngine.Debug:LogError(Object)
NetManager:OnNetworkConnect(Boolean, String) (at Assets/Scripts/Game/NetManager.cs:170)
System.Reflection.MethodBase:Invoke(Object, Object[])
TNet.UnityTools:Broadcast(String, Object[]) (at Assets/TNet/Client/TNUnityTools.cs:41)
TNManager:OnConnect(Boolean, String) (at Assets/TNet/Client/TNManager.cs:740)
TNet.GameClient:ProcessPacket(Buffer, IPEndPoint) (at Assets/TNet/Client/TNGameClient.cs:718)
TNet.GameClient:ProcessPackets() (at Assets/TNet/Client/TNGameClient.cs:535)
TNManager:Update() (at Assets/TNet/Client/TNManager.cs:725)

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
You sure that's where you get it? Your stack trace points at your own class, NetManager, after using Broadcast to notify something.

Looks like you have a function with the name it expects (OnNetworkConnect), but your set of arguments for that function is wrong. It needs (bool, string).

andrew

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 44
    • View Profile
Here's my OnNetworkConnect().  I copied it from TNAutoJoin.cs

  1.         /*
  2.         -----------------------
  3.         OnNetworkConnect()
  4.         on success, join a channel
  5.         -----------------------
  6.         */
  7.         void OnNetworkConnect( bool result, string message ) {
  8.                 if ( result ) {
  9.                         Debug.LogWarning( "Connected > Joining channel." );
  10.                         TNManager.JoinChannel( channelID, "" );
  11.                 } else if ( !string.IsNullOrEmpty( failureFunctionName ) ) {
  12.                         UnityTools.Broadcast( failureFunctionName, message );
  13.                         autoConnect = false;
  14.                 } else {
  15.                         Debug.LogError( message );     
  16.                         autoConnect = false;
  17.                 }
  18.         }
  19.  

The callstack is from the Debug.LogError( message ) in the code above.  Oh.. and I'd debug the TNGameClient but Unity freezes if I set a breakpoint in Monodevelop in TNGameClient.  Is there a trick to stable debugging of these connection issues?  Perhaps I need to reboot.

One other thing.. If I call connect with just TNManager.Connect( ent.externalAddress.ToString() ), I get connection refused.  Calling with the internal address works fine.  Is it possible my Airport Extreme just doesn't allow me to go out and back, and the "Invalid Arguments" is a result of that?
« Last Edit: February 28, 2013, 11:27:43 AM by andrew »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Unless the port is open on your router (do you use UPnP?), connecting to yourself using an external address will fail. Some routers also actively prevent the ability to connect to a local computer using an external address. The cable modem router I have is like that, for example.

UnityTools.Broadcast( failureFunctionName, message ); <-- why not simply have OnNetworkConnect function in wherever you have "failureFunctionName"? You will avoid an extra broadcast.

andrew

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 44
    • View Profile
I'll mess with my router and see if it clears that up.  I was under the impression UPnP was automatic?

UnityTools.Broadcast() etc was a left over from TNAutoJoin.. I don't actually use it, but thanks.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
UPnP is automatic if you run the server executable, or actually use the UPnP class.

andrew

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 44
    • View Profile
More on this for anyone running into the same problems.

After dropping in UPnP, I still had the same error messages.  Turns out an Apple Airport Extreme router doesn't support UPnP.  You just have to open the ports in the Airport Utility.

blueskined

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 26
    • View Profile
I got the similar issue, but couldn't figure out why, I got some help from Michael, but it didn't work out, I am paused for now, just wait for the update, and check again - like the early stage of ngui :) . (anyway, the game we planning will be using standalone server, I am not rushing on this. I hope it can be fixed in future release of tnet.)