"Server can't bind" for host on Meta Quest 2 | UnityTransport, LAN

Hello ,

Thank you very much for your reply. I took some time to thoroughly look into your pointers and it eventually lead me to the solution (…or maybe it’s more a workaround?).
I’ll start describing how I solved my problem since it’s the main subject of this thread and, for the people who may be interested, I give a quick overview on how to check that you have the correct Android permissions at the end of this answer.
Also, I may have stumbled upon a bug for UnityTransport NetworkManager.StartClient but I’m not sure: it may be that I misunderstood the true meaning of the bool that is returned by that method. So, @simon-lemay-unity , if you could be kind enough to check what I wrote on that, that would be nice :slight_smile:

Solution (workaround?) to my issue
The puzzling point for me was that the code I wrote for host/client architecture was working just fine if I was using it for on Windows PCs but it kept failing on Meta Quest 2. Since the most obvious difference at first between the two platforms was their differences in OS, I thought there may be additional stuffs to enable on Android. Which is true since you need permission for INTERNET as Simon told me. I checked that (see below for how I did that), the INTERNET permission was already added and ACCESS_NETWORK_STATE didn’t make any difference, however.
So I continued by investigating the listen address of the server (the third optional parameter of SetConnectionData that Simon also suggested me) and I finally found out that my app was actually able to start a server as expected on localHost (127.0.0.1), but only at launch.

A little note (this is super basic stuff but everybody has to be a beginner first):
For those who don’t know, you can check the [netstat](https://en.wikipedia.org/wiki/Netstat) for the Quest thanks to SideQuest. You can run adb commands from SideQuest by clicking the icon on the top right corner which looks like a rectangle with an arrow. So, with your Quest connected (for me USB 3.0 cable) you run adb shell netstat -a. Other options here.
End of the note

So, if the app could launch the server on the very beginning, but was not able to change to the address I was feeding it, the problem was probably in my Restart() method.
Here is the simplified code:

IEnumerator Restart()
        {
            // we shut down the previous instance of the server
            NetworkManager.Shutdown();

            yield return new WaitForEndOfFrame();
         
            // we start the new server
            // Unitytransport Connection Data was updated before starting this Coroutine
            bool isHostStarted = NetworkManager.StartHost();

            // If something fails while Unitytransport attempts to start the Host
            if (!isHostStarted)
            {
                //Going back to 127.0.0.1
            }
        }

You may immediately spot the yield return new WaitForEndOfFrame(); because you have a fresh eye on the stuff. But I have been overlooking that line for about 30 hours by the time I saw it again…
Turns out that this Restart() was not working on PC either when I first wrote it. But I had completely forgotten about it. Adding yield return new WaitForEndOfFrame(); was mandatory if I wanted the expected behavior “ShutDown current instance then Starts the new one” to complete.
Actually, if one wants the server to restart as expected then, rather than waiting for the end of the frame which is performance dependent (hence, working on PC but not on Quest 2!!!), you have to wait that the previous instance has stopped listening. Effectively, you write yield return new WaitWhile(() => NetworkManager.IsListening); instead.
Aside overlooking that line of code, what mislead me was the LogError in the Unity console which was saying “Server couldn’t bind”. That lead me to assume that the error was in my way to handle the IP/Port data when the actual problem lied in how long it takes for UnityTransport to indeed shut down the server after calling NetworkManager.ShutDown(). What is even more misleading is that, if you attempt to launch a server with NetworkManager.StartHost before NetworkManager.ShutDown() the LogError explicitely tells you that you cannot start a new instance while one is already running.

So, @simon-lemay-unity , is this a correct way of restarting a host? Did I overlook a recommended method? Is it normal that NetworkManager.ShutDown() seems to take quite a few milliseconds to finish? Is this written somewhere in the documentation and I didn’t see it?
This list of questions may feel aggressive, but I assure you there is no animosity on my side. It’s just professional curiosity:slight_smile:

Now, NetManager.StartClient always returns True:
So, now that I dealt with starting a Host to the correct IP/Port address, I still need other players to join the host, right? Considering that, when a player starts the app, they are all their own host (at 127.0.0.1), I also have to shut down that instance and then restart a new one with the IP/Port of the new host.
yield return new WaitWhile(() => NetworkManager.IsListening); Still works wonders before attempting to start the client.
BUT, @simon-lemay-unity , NetworkManager.StartClient always returns TRUE even when I give it the wrong IP/Port information. Let’s say I tell it to connect to IP “192.”, then there is a LogError saying that it could not parse the IP (obviously) but NetworkManager.StartClient still returns TRUE. Same if I give it a complete IP/Port information that points to nothing listening (like “10.5.2.3:8080” or whatever other possibility).
Is this the expected behaviour or is it a bug? Because I checked the code and there are situations where NetworkManager.StartClient should return FALSE. If it always returns TRUE, how is one supposed to check that the client successfully connected to the host?
Maybe I should start another thread for that…?

Checking Android Permissions:
There a other accessible resources on the web about editing the Android Manifest and declaring permissions in Unity. This Unity Forum Thread is the most recent information I found about it but it actually took me a few trials with different keywords to find it on the internet. Otherwise, I found a lot of deprecated information.
So, this is a copy of the solution from the thread above but I do it for the sake of sharing.

To check the content of the Android Manifest that Unity generates automatically through Gradle when building your app, I recommend using Jadx to decompile you .apk file. It took me 30 sec to install and opened my app under 2 sec. I suppose this depends how big you app is, however. Jadx needs Java.
Then, in the “resources” folder, you can find AndroidManifest.xml.
If you want to customize the content of your manifest then, as Simon said, there is a checkbox in the Android player settings. Once checked, you will have a template available in your project. You add stuffs in there and it will be appended to the final version of the manifest that Unity generates upon build.

1 Like