NAT Traversal for UNET
Provides NAT punch-through, automatic port forwarding, and other useful features on top of Unity's UNET HLAPI networking system.
NATHelper Class Reference

Provides methods for performing NAT punch-through and automatic port forwarding. More...

Inherits MonoBehaviour.

Public Member Functions

virtual void Awake ()
 Starts the message loop where all RakNet messages are received and handled. More...
 
IEnumerator connectToNATFacilitator ()
 Connect to the externally hosted Facilitator. Assign guid. More...
 
void DisconnectFromFacilitator (uint blockDuration=0, bool sendDisconnectNotification=false)
 Disconnect from the Facilitator, shut down raknet, stop all punchthrough. More...
 
void findNatDevice (Action< bool > onDoneSearchingForNATDevice=null)
 Search for a router between the client and the internet so that we can forward ports on it More...
 
void listenForPunchthroughResponse (Packet packet)
 
void mapFacilitatorPort ()
 Forward the port that is used to connect to the Facilitator. More...
 
void mapPort (int privatePort, int publicPort=0, int lifetime=0, Protocol protocol=Protocol.Both, string desc="", Action< Mapping, bool, Exception > onPortMappingDone=null)
 Attempt to forward a port so that peers behind a router can receive external connections. More...
 
IEnumerator messageLoop ()
 All raknet messages are handled here. This gets called in Awake() and runs forever. You should never need to call this manually but I made it public just in case... More...
 
void OnDestroy ()
 Shuts down raknet, clears port mappings More...
 
void OnDrawGizmos ()
 
void printPortMappings ()
 Prints all port mappings. Useful for debugging. More...
 
IEnumerator punchThroughToServer (ulong hostGUIDlong, Action< int, int, bool > onHolePunched)
 Punch a hole from a client to the server identified by hostGUID More...
 
void RemoveAllPortMappings ()
 
IEnumerator startListeningForPunchthrough (Action< int, ulong > onHolePunched)
 Call on the server to start listening for clients trying to punch through More...
 
void StopListeningForPunchthrough ()
 Stop listening for punchthrough on the server More...
 
void stopPortForwarding ()
 Stop any active port mapping tasks. Also stops searching for NAT devices. More...
 
void StopPunchingThrough ()
 Stop trying to punch-through on the client More...
 
virtual void Update ()
 

Public Attributes

SystemAddress facilitatorAddress
 The SystemAddress of the Facilitator that is currently connected to (if any). More...
 
string facilitatorIP = "grabblesgame.com"
 The IP address of the server running the Facilitor More...
 
ushort facilitatorPort = 61111
 The port that the Facilitator was started on (default 61111). More...
 
float facilitatorRetryAttempts = 3
 How many times to attempt to connect to the Facilitator before giving up. More...
 
float facilitatorTimeOut = 10
 How long to wait before timing out when connecting to the facilitor. More...
 
ulong guid
 The unique identifier of each peer connected to the Facilitator. More...
 
bool isConnectingToFacilitator
 This will be set true as soon as init() is called. By default this happens in NetworkManager.Start(). Once a connection to the Facilitator has been established this will be set to false. The host will also reconnect to the Facilitator after each new client connection in order to be ready to accept the next client connection. More...
 
bool isListeningForPunchthrough
 A host isListeningForPunchthrough as soon as StartHostAll() is called and the Facilitator has been connected to. This will never be set true if connectPunchthrough is not enabled. More...
 
bool isPunchingThrough
 A client isPunchthingThrough after they call StartHostAll() and before a succesful connection to a client is made. Once a connection is made the client is no longer punchthing through. This will never be set true if connectPunchthrough is not enabled. More...
 
bool portForwardingEnabled = true
 Set to true to enable automatic-port forwarding. More...
 
float portForwardingTimeOut = 10
 How long to wait before timing out when searching for upnp/pmp enabled devices or forwarding ports. More...
 
float punchthroughTimeout = 30
 
RakPeerInterface rakPeer
 This will be set once the facilitator has been connected More...
 

Static Public Attributes

static NATHelper singleton
 This is just an easy way to get an access to the NATHelper since there will generally only be one instance of it at a time. More...
 

Properties

bool hasFailedToConnectToFacilitator [get]
 Check if the the connection to the Facilitator failed. More...
 
bool isConnectedToFacilitator [get]
 Check if the Facilitator has been connected to and a guid has been assigned. More...
 
bool isDoneFindingNATDevice [get]
 This will be set to true when either a upnp device is discovered or searching has timed out. More...
 
bool isForwardingPort [get]
 
NatDevice natDevice [get]
 This will be set when a upnp device has been discovered More...
 

Events

Action< ulong > OnDoneConnectingToFacilitator
 Subscribe to this event to be notified when the Facilitator has been connected to. The method will be passed the guid that was assigned by the Facilitator. If the guid is 0 then connection failed. More...
 

Detailed Description

Provides methods for performing NAT punch-through and automatic port forwarding.

Once a hole is punched a connection can be made via the UNet HLAPI or whatever other networking system you want. Punch-though requires the included Facilitator to be running on an externally hosted server pointed to by facilitatorIP.

Member Function Documentation

◆ Awake()

virtual void Awake ( )
virtual

Starts the message loop where all RakNet messages are received and handled.

◆ connectToNATFacilitator()

IEnumerator connectToNATFacilitator ( )

Connect to the externally hosted Facilitator. Assign guid.

◆ DisconnectFromFacilitator()

void DisconnectFromFacilitator ( uint  blockDuration = 0,
bool  sendDisconnectNotification = false 
)

Disconnect from the Facilitator, shut down raknet, stop all punchthrough.

◆ findNatDevice()

void findNatDevice ( Action< bool >  onDoneSearchingForNATDevice = null)

Search for a router between the client and the internet so that we can forward ports on it

This is an asynchronous method. It will return immediately but a device is not actually found until isDoneFindingNATDevice = true. You should call this as early as possible so that a device will be ready when you try to mapPort. If you call mapPort before a device is found it will wait for the device to be found. If you call mapPort without first calling findNatDevice it will call it for you and wait for the device to be found.

◆ mapFacilitatorPort()

void mapFacilitatorPort ( )

Forward the port that is used to connect to the Facilitator.

◆ mapPort()

void mapPort ( int  privatePort,
int  publicPort = 0,
int  lifetime = 0,
Protocol  protocol = Protocol.Both,
string  desc = "",
Action< Mapping, bool, Exception >  onPortMappingDone = null 
)

Attempt to forward a port so that peers behind a router can receive external connections.

Parameters
privatePortThe private port.
publicPortThe public port.
lifetimeHow long before the mapping expires. Set to 0 to never expire.
protocolThe protocol (UDP / TCP / BOTH).
descA description for the port mapping. Probably the name of your game.
onPortMappingDoneThe method to call when port mapping is finished. If you are creating a tcp and udp mapping at the same time then onPortMappingDone will be called twice.

◆ messageLoop()

IEnumerator messageLoop ( )

All raknet messages are handled here. This gets called in Awake() and runs forever. You should never need to call this manually but I made it public just in case...

◆ OnDestroy()

void OnDestroy ( )

Shuts down raknet, clears port mappings

◆ printPortMappings()

void printPortMappings ( )

Prints all port mappings. Useful for debugging.

◆ punchThroughToServer()

IEnumerator punchThroughToServer ( ulong  hostGUIDlong,
Action< int, int, bool >  onHolePunched 
)

Punch a hole from a client to the server identified by hostGUID

Once the hole is punched onHolePunched will be called with the ports to use to connect

Parameters
hostGUIDThe host unique identifier.
onHolePunchedThe method to call when a hole is succesfully punched.

◆ RemoveAllPortMappings()

void RemoveAllPortMappings ( )

Unmap mapped ports

◆ startListeningForPunchthrough()

IEnumerator startListeningForPunchthrough ( Action< int, ulong >  onHolePunched)

Call on the server to start listening for clients trying to punch through

When the server receives a punch-through from the client, onHolePunched will be called with the port that the server should listen for incoming connections on.

Parameters
onHolePunchedThe method to call when a punch-through is received from a client.

◆ StopListeningForPunchthrough()

void StopListeningForPunchthrough ( )

Stop listening for punchthrough on the server

◆ stopPortForwarding()

void stopPortForwarding ( )

Stop any active port mapping tasks. Also stops searching for NAT devices.

◆ StopPunchingThrough()

void StopPunchingThrough ( )

Stop trying to punch-through on the client

Member Data Documentation

◆ facilitatorAddress

SystemAddress facilitatorAddress

The SystemAddress of the Facilitator that is currently connected to (if any).

Due to a quirk in how SystemAddress works, if you want to check if this has not been set you have to do

if (!(facilitatorSystemAddress == null)) ...

as opposed to

if (facilitatorSystemAddress != null) ...

which will throw a compiler error. Yay programming.

◆ facilitatorIP

string facilitatorIP = "grabblesgame.com"

The IP address of the server running the Facilitor

◆ facilitatorPort

ushort facilitatorPort = 61111

The port that the Facilitator was started on (default 61111).

◆ facilitatorRetryAttempts

float facilitatorRetryAttempts = 3

How many times to attempt to connect to the Facilitator before giving up.

◆ facilitatorTimeOut

float facilitatorTimeOut = 10

How long to wait before timing out when connecting to the facilitor.

◆ guid

ulong guid

The unique identifier of each peer connected to the Facilitator.

Identifier used by clients to tell the NATHelper which host to punch a hole to. This will not be set until hasConnectedToFacilitator = true. If you are using this class directly you'll need some way to pass the guid from the host to the clients. The way this NetworkManager does it is by including the guid in the match name when hosting the UNET match. The clients then parse the guid from name of each match in OnMatchList().

◆ isConnectingToFacilitator

bool isConnectingToFacilitator

This will be set true as soon as init() is called. By default this happens in NetworkManager.Start(). Once a connection to the Facilitator has been established this will be set to false. The host will also reconnect to the Facilitator after each new client connection in order to be ready to accept the next client connection.

if !isConnectingToFacilitator and guid == 0 then the Facilitator could not be connected to and punch-through will not be possible.

◆ isListeningForPunchthrough

bool isListeningForPunchthrough

A host isListeningForPunchthrough as soon as StartHostAll() is called and the Facilitator has been connected to. This will never be set true if connectPunchthrough is not enabled.

◆ isPunchingThrough

bool isPunchingThrough

A client isPunchthingThrough after they call StartHostAll() and before a succesful connection to a client is made. Once a connection is made the client is no longer punchthing through. This will never be set true if connectPunchthrough is not enabled.

◆ portForwardingEnabled

bool portForwardingEnabled = true

Set to true to enable automatic-port forwarding.

◆ portForwardingTimeOut

float portForwardingTimeOut = 10

How long to wait before timing out when searching for upnp/pmp enabled devices or forwarding ports.

◆ rakPeer

RakPeerInterface rakPeer

This will be set once the facilitator has been connected

if isDoneConnectionToFacilitator and rakPeer = 0 then the Facilitator could not be connected to and punch-through will not be possible.

◆ singleton

NATHelper singleton
static

This is just an easy way to get an access to the NATHelper since there will generally only be one instance of it at a time.

This gets set in Awake() and unset in OnDestroy(). If for some reason you are using more than one NATHelper instance at a time you should not use this property as the behviour is undefined.

Property Documentation

◆ hasFailedToConnectToFacilitator

bool hasFailedToConnectToFacilitator
get

Check if the the connection to the Facilitator failed.

This is equivalent to !isConnectingToFacilitator && guid == 0;

◆ isConnectedToFacilitator

bool isConnectedToFacilitator
get

Check if the Facilitator has been connected to and a guid has been assigned.

◆ isDoneFindingNATDevice

bool isDoneFindingNATDevice
get

This will be set to true when either a upnp device is discovered or searching has timed out.

If isDoneFindingNATDevice and natDevice == null then no upnp enabled device was found and automatic port-forwarding will not be possible.

◆ natDevice

NatDevice natDevice
get

This will be set when a upnp device has been discovered

If isDoneFindingNATDevice and natDevice == null then no upnp enabled device was found and automatic port-forwarding will not be possible.

Event Documentation

◆ OnDoneConnectingToFacilitator

Action<ulong> OnDoneConnectingToFacilitator

Subscribe to this event to be notified when the Facilitator has been connected to. The method will be passed the guid that was assigned by the Facilitator. If the guid is 0 then connection failed.