Host Availability Check

Hello there,

for a project of ours, we’re trying to support Hosts located behind NATs without requiring the user to manually configure Ports in their router/similar devices. UDP Hole Punching seems to be necessary to be done, but it would be better to verify afterwards that the Host is reachable.

With TCP, it would be easy: open a connection, if the connection could be opened, someone is listening, close the connection again.
UDP doesn’t know anything about connections, so a package would need to be sent where the received will respond to. But it doesn’t seem so far as if custom UDP messages are supported by Netcode (or Unity Transport), so a message would need to be crafted that would cause the Host to respond in some way. Afterwards, another message probably should be sent that lets the Host forget about this “connection” again without to much overhead/effort, but this second message might really be optional.

(The Server performing this check is not related to DOTS at all, and using a Client based on Unity and DOTS probably would be way to much overhead.)

Does already someone know how this message(s) would need to look like? Or does someone know how this could be evaluated?

Thanks in advance for any Help and Hints.

If you want to host behind Nat, the best I would suggest is to use the Relay service Unity provide. That is easy to integrate with Transport and will provide a very good connectivity to you game.

Implementing a custom NAT traversal requires way more work than just sending a message to server. Is not even a matter of custom UDP messages, but a real and proper NAT handling, that requires still some servers to handle the initial public and internal port exchanges (with all the eventual complication of port guessing etc etc).

If you are using transport 2.0, they have a good example how to set it up.

Speaking about NetCode, we are planning to release a sample showing how to integrate the Relay service as well.

The service is not free (but has a very reasonable price target).

Transport does not allow to send custom “handshake” messages for the initial connection. By setting up a reasonable timeout however you can still say that if after 2 second you are not connect probably the server is not reachable.

If you want to have a complete control you need to open you own socket and design your connection handshaking for verifying the server connectivity.

For this are u refer to port forwarding?

The part about NAT and UDP Hole Punching (or similar techniques) was mostly just background information. To be honest, I forgot to mention that this availability check is not just used to verify that this process above worked, but also to verify that the Host is still there, my bad. It’s supposed to be used on a server the client will utilize for a server search for available hosts (at least in the first version of the game).

This is why “just a single UDP message” is enough - because this thread is really just about determining whether or not there’s a Host behind a certain IP address + Port combination.

Yes, using certain Unity services for this would seemingly be an option, but might not address all of our requirements.

Well, yes and no. NAT stands for Network Address Translation and is commonly used to translate a public IP address (the one your provider assigns to your network) and port combination to a local IP address and port. Usually, when requests lead out of the network, the router forwards the request, opens a port for the response, and uses this port (and its own public IP address) to detect the response and forward it to the local device.
Port Forwarding is the static configuration of certain ports for which incoming requests should be forwarded to a predefined local device.

But if you develop a game, you usually would like the player not having to do any configurations. You could achieve that by dynamically configure the router from within the game (which as far as I’m aware isn’t enabled on all routers by default), or you could try to “open” a port through UDP hole punching or similar techniques, which then wouldn’t be called “Port Forwarding” (at least according to my understanding, since no configuration is involved).

Please keep in mind though that this thread is about the availability check, i. e. a “Ping” to the server, but ideally on the same port that’s also used by the game. (Otherwise, if e. g. the regular ping is used, the router itself might respond without forwarding anything, so the Host would be determined to be available basically “forever”.)

If you are using port forwarding on the server or/and on the client things are different. Because the mapping become explicit connection become possible.
You may still need a STUN server to setup the connection though, if the server is not configured to forwards port or have some special mapping rules.

Could you use connection approval together with the connection payload? That way, the server/host would know that the request was just to “ping availability” and denies the connection, so as to not interfere with regular gameplay.

I’m not so certain if I understood you properly here. I read your message as: “Can you determine on the Host (the Netcode Server for which the check is performed) if a UDP message is just a ping and [act accordingly]?”
If this is what you want to ask: I honestly don’t know. I tried briefly to get a look into what is happening behind the scenes (the Netcode and the Transport packages are involved there), but I didn’t stumble upon a way to add a custom UDP message handler, or anything to deal with messages on a lower level than having Ghosts getting synchronized automatically and RPCs sent around. This definitely doesn’t mean that there’s nothing out there, but I’m not aware of anything yet. (An my assumption would be that this might not be possible, since this could severly interfere with Netcode and the regular entity synchronization, but here I’m just guessing around to be honest.)

If this is not what you wanted to ask, could you please elaborate a bit more?

I’m thinking of this:

“The ConnectionApprovalRequest.Payload parameter takes any custom data of your choice that the client should send to the server.”

So you can send the host anything BEFORE a client connection is made (approved).

However, scanning through the docs, I don’t see an immediate “response” message returned to the client:

Sounds like it could work, if I was using Netcode for GameObjects, but I’m using Netcode for DOTS (which is why we are in the DOTS subforum). Is there something similar for Netcode for DOTS?

Netcode is Netcode, isn’t it? :smile:
Not sure what the differences are. I would assume a relative feature-parity, for at least the basic stuff like connection approval.

NetCode for Entities is based on transport as NetCode for GameObject.

The NetCode for Entities is designed to let you send RPC or GhostSnapshots. We don’t allow expanding the protocol. Also, just to clarify, the transport has a connection concept. It manages timeout, it already keep the connection alive (in 2.0) etc etc. It is not just pure UDP.
If you can’t connect to the server (because of Nat) the connection will fail, after the timeout you set anyway.

But, even though you can technically send though any kind of message with transport, as simple as getting a data stream writer, write the serialized data into it and queuing into the pipeline you want to send it, we don’t recognise custom user data that way.
When we parse the message, we only recognise the two type of messages I mentioned before (because this is by design).

Unfortunately, you can’t inject yourself in the initial handshake in Transport either at the moment.
As far as I know, you need to modify the packet to ad a custom connection handshake message (that it is what you actually looking for).

The way transport work is pretty simple: create a NetworkDriver , poll the connection events and handle the message types you receive. That it.

The connection is made (by sending a few internal control message bytes) and when the client and server finally talk, then you can start sending any message you want.
On top of that you can really build any other logic you want. And this is in fact what the NetCode for GameObject does.

If you want to ping the server in your way, before connecting for the game or for just sake of reporting it is alive to a matchmaking service, I think you have two/half options right now.

Option 1
If you don’t care opening another port (that make sense in my opinion anyway) you can achieve it by creating another driver and start listening on it (on the server) and using it for checking the server present (before doing the actual connection if you need so).
After you accepted the incoming connection (that you can’t inject into anyway, even at driver level unless you write your own underlying layer) then you can send your custom message, handle it, eventually retry sending it (etc etc).

I’m advocating about using another connection port because, if you actually use the game driver, all of a sudden you need to keep in consideration you need to increase the incoming packet queues sizes, connections etc just for sake of some clients/service polling you.
That is is really not what you want. Also there are other stuff you may want to report there (not just ping) and maybe instead of being polled, you need to actually send messages on a regular basis to other services.
Furthermore, this pinging action does not disrupt the game experience.
So it is a more scalable and robust solution.

Because, again, this is really a ping, I think having the full driver stack for this seems also like too much.
Probably just opening a simple udp socket for that purpose is more than enough. That also remove the problem that you need to create a connection first.

Option 2
Modify the current NetworkStreamReceiveSystem. That can be quite a little more more involved task.
The NetCode for Entities connection is constituted by two phases:

  • First the client connect.
  • A protocol information is exchanged by client and server to verify they can deserialise the same ghosts and rpc types. That requires having game data. So it is not ideal for an external service that probe the server.

Because of that, you need to have a new way to handling the incoming connection. You probably need to wait before exchanging the protocols data and instead sending your custom message etc etc. You need in practice to create another sort of handshacking phase.
Looks like to me a really bad choice.

Option 2b
Modify the underlying transport layer. Now here depend which version of the transport you are dealing with.
I would not do that either.

1 Like