![]() |
How to use combine UPNP, NAT type detection, NAT punchthrough, and Router2 so P2P connections complete quickly and efficiently RakNet offers 5 systems, each of which deal partly with not being able to connect to other systems. These systems are:
First, I'll describe the complete solution in case you are writing a major backend, or a massively multiplayer game. Skip to the bottom of this page if you want to just do things "the easy way". Step 1: Connect to the server Connect to your server running NATCompleteServer using the usual method RakPeerInterface::Connect(). Step 2: Detect router type Call NatTypeDetectionClient::DetectNATType(). You should get back a packet ID_NAT_TYPE_DETECTION_RESULT indicating the NAT type. For example: if (packet->data[0]==ID_NAT_TYPE_DETECTION_RESULT)
{ If detectionResult is NATTypeDetectionResult::NAT_TYPE_NONE then this system does not have a router. You can connect to every system, and every system can connect to you. You should tell the server this system is directly connectable, so that incoming systems do not waste time trying to do NAT punch to this system. See Appendix A, passing NAT_TYPE_NONE. Connect to every existing user in the game session. Step 3: Use UPNP to open the router Assuming our router in step 2 was not NATTypeDetectionResult::NAT_TYPE_NONE, we are going to try to use UPNP to open the router. To build MiniUPNP
#include "miniupnpc.h" #include "upnpcommands.h" #include "upnperrors.h" bool OpenUPNP(RakPeerInterface *rakPeer, SystemAddress serverAddress) { struct UPNPDev * devlist = 0; devlist = upnpDiscover(2000, 0, 0, 0); if (devlist) { char lanaddr[64]; /* my ip address on the LAN */ struct UPNPUrls urls; struct IGDdatas data; if (UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr))==1) { DataStructures::List< RakNetSmartPtr< RakNetSocket> > sockets; rakPeer->GetSockets(sockets); char iport[32]; Itoa(sockets[0]->boundAddress.GetPort(),iport,10); char eport[32]; Itoa(rakPeer->GetExternalID(serverAddress).GetPort(),eport,10); int r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, eport, iport, lanaddr, 0, "UDP", 0); if(r!=UPNPCOMMAND_SUCCESS) { return false; } } else { return false; } } else { return false; } return true; }If OpenUPNP returned true, you are done. You can connect to every system, and every system can connect to you. Remote systems should connect to your external port as seen by the server. You should tell the server this system is directly connectable, so that incoming systems do not waste time trying to do NAT punch to this system. See Appendix A, passing NAT_TYPE_SUPPORTS_UPNP. Connect to every existing user in the game session. Step 4: Run NATPunchthroughClient
For each player that we called OpenNAT for, we should get one of the following response codes:
Step 5: Use Router2 or UDPProxyClient (optional) For players that failed NATPunchthrough, you can route their connections through players that did not fail, using the Router2 plugin. You can also use the UDPProxyClient while you are running your own UDPProxyServer to forward those connections through a server. Router2 will return ID_ROUTER_2_FORWARDING_NO_PATH if forwarding is not possible and ID_ROUTER_2_FORWARDING_ESTABLISHED on success. UDPPRoxyClient will return ID_UDP_PROXY_GENERAL. Byte 1 indicates the return value. Success is returned on ID_UDP_PROXY_FORWARDING_SUCCEEDED. The remote system will get ID_UDP_PROXY_FORWARDING_NOTIFICATION on success. Anything else means failure. If these solutions fail, or you do not use them, then it is not possible to complete a peer to peer gaming session. Leave the game session on the server. You should show a dialog box to the user that they need to manually open ports on their router before they can play. Or you can just try a different session. Step 6: Connect to all other players in the session that we did not already connect to. Step 6 assumes all users that failed connectivity were already connected to in step 5. If not, leave the game session on the server. You should show a dialog box to the user that they need to manually open ports on their router before they can play. For players previously marked with NAT_TYPE_NONE, NAT_TYPE_SUPPORTS_UPNP, or that passed NAT punchthrough, you should now connect to these users. You can assume the connections will complete. See the sample \Samples\NATCompleteClient |
The easy way |
Just UPNP and NatPunchthroughClient UPNP enabled routers are common these days. Therefore, this simpler solution will work in nearly all cases, and is recommended unless you are writing a back-end service with multiple fallbacks.
See the sample \Samples\ComprehensivePCGame |
![]() |