/* * Original work: Copyright (c) 2014, Oculus VR, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * RakNet License.txt file in the licenses directory of this source tree. An additional grant * of patent rights can be found in the RakNet Patents.txt file in the same directory. * * * Modified work: Copyright (c) 2016-2021, SLikeSoft UG (haftungsbeschränkt) * * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style * license found in the license.txt file in the root directory of this source tree. */ #include "slikenet/peerinterface.h" #include "slikenet/sleep.h" #include #include #include #include // used for std::numeric_limits #include "slikenet/Kbhit.h" #include "slikenet/MessageIdentifiers.h" #include "slikenet/BitStream.h" #include "slikenet/sleep.h" #include "slikenet/NatPunchthroughClient.h" #include "slikenet/NatTypeDetectionClient.h" #include "slikenet/Getche.h" #include "slikenet/GetTime.h" #include "slikenet/Router2.h" #include "slikenet/UDPProxyClient.h" #include "slikenet/Gets.h" #include "slikenet/Itoa.h" #include "slikenet/linux_adapter.h" #include "slikenet/osx_adapter.h" // To include miniupnp, see Samples\NATCompleteClient\readme.txt #include "miniupnpc.h" #include "upnpcommands.h" #include "upnperrors.h" using namespace SLNet; #define DEFAULT_RAKPEER_PORT 50000 #define RAKPEER_PORT_STR "0" #define DEFAULT_SERVER_PORT "61111" #define DEFAULT_SERVER_ADDRESS "natpunch.slikesoft.com" enum SampleResult { PENDING, FAILED, SUCCEEDED }; #define SUPPORT_UPNP FAILED #define SUPPORT_NAT_TYPE_DETECTION FAILED #define SUPPORT_NAT_PUNCHTHROUGH PENDING #define SUPPORT_ROUTER2 FAILED #define SUPPORT_UDP_PROXY FAILED struct SampleFramework { virtual const char * QueryName(void)=0; virtual bool QueryRequiresServer(void)=0; virtual const char * QueryFunction(void)=0; virtual const char * QuerySuccess(void)=0; virtual bool QueryQuitOnSuccess(void)=0; virtual void Init(SLNet::RakPeerInterface *rakPeer)=0; virtual void ProcessPacket(Packet *packet)=0; virtual void Update(SLNet::RakPeerInterface *rakPeer)=0; virtual void Shutdown(SLNet::RakPeerInterface *rakPeer)=0; SampleResult sampleResult; }; SystemAddress SelectAmongConnectedSystems(SLNet::RakPeerInterface *rakPeer, const char *hostName) { DataStructures::List addresses; DataStructures::List guids; rakPeer->GetSystemList(addresses, guids); if (addresses.Size()==0) { return SLNet::UNASSIGNED_SYSTEM_ADDRESS; } if (addresses.Size()>1) { printf("Select IP address for %s.\n", hostName); char buff[64]; for (unsigned int i=0; i < addresses.Size(); i++) { addresses[i].ToString(true, buff, static_cast(64)); printf("%i. %s\n", i+1, buff); } Gets(buff,sizeof(buff)); if (buff[0]==0) { return SLNet::UNASSIGNED_SYSTEM_ADDRESS; } unsigned int idx = atoi(buff); if (idx<=0 || idx > addresses.Size()) { return SLNet::UNASSIGNED_SYSTEM_ADDRESS; } return addresses[idx-1]; } else return addresses[0]; }; SystemAddress ConnectBlocking(SLNet::RakPeerInterface *rakPeer, const char *hostName, const char *defaultAddress, const char *defaultPort) { SystemAddress returnvalue = SLNet::UNASSIGNED_SYSTEM_ADDRESS; char ipAddr[64]; if (defaultAddress==0 || defaultAddress[0]==0) printf("Enter IP of system %s is running on: ", hostName); else printf("Enter IP of system %s, or press enter for default: ", hostName); Gets(ipAddr,sizeof(ipAddr)); if (ipAddr[0]==0) { if (defaultAddress==0 || defaultAddress[0]==0) { printf("Failed. No address entered for %s.\n", hostName); return SLNet::UNASSIGNED_SYSTEM_ADDRESS; } else { strcpy_s(ipAddr, defaultAddress); } } char port[64]; if (defaultAddress==0 || defaultAddress[0]==0) printf("Enter port of system %s is running on: ", hostName); else printf("Enter port of system %s, or press enter for default: ", hostName); Gets(port, sizeof(port)); if (port[0]==0) { if (defaultPort==0 || defaultPort[0]==0) { printf("Failed. No port entered for %s.\n", hostName); return SLNet::UNASSIGNED_SYSTEM_ADDRESS; } else { strcpy_s(port, defaultPort); } } const int intPort = atoi(port); if ((intPort < 0) || (intPort > std::numeric_limits::max())) { printf("Failed. Specified port %d is outside valid bounds [0, %u]", intPort, std::numeric_limits::max()); return SLNet::UNASSIGNED_SYSTEM_ADDRESS; } if (rakPeer->Connect(ipAddr, static_cast(intPort), 0, 0)!= SLNet::CONNECTION_ATTEMPT_STARTED) { printf("Failed connect call for %s.\n", hostName); return SLNet::UNASSIGNED_SYSTEM_ADDRESS; } printf("Connecting...\n"); SLNet::Packet *packet; // #med - review --- at least we'd add a sleep interval here - also review whether the behavior is correct to only check the very first received packet (old RakNet code was bogus in this regards) do { packet = rakPeer->Receive(); } while (packet == nullptr); if (packet->data[0] == ID_CONNECTION_REQUEST_ACCEPTED) returnvalue = packet->systemAddress; else if (packet->data[0] == ID_NO_FREE_INCOMING_CONNECTIONS) printf("ID_NO_FREE_INCOMING_CONNECTIONS"); rakPeer->DeallocatePacket(packet); return returnvalue; } struct UPNPFramework : public SampleFramework { UPNPFramework() { sampleResult=SUPPORT_UPNP;} virtual const char * QueryName(void) {return "UPNPFramework";} virtual bool QueryRequiresServer(void) {return false;} virtual const char * QueryFunction(void) {return "Use UPNP to open the router";} virtual const char * QuerySuccess(void) {return "Other systems can now connect to you on the opened port.";} virtual bool QueryQuitOnSuccess(void) {return true;} virtual void Init(SLNet::RakPeerInterface *rakPeer) { if (sampleResult==FAILED) return; struct UPNPDev * devlist = 0; devlist = upnpDiscover(2000, 0, 0, 0, 0, 0); if (devlist) { printf("List of UPNP devices found on the network :\n"); struct UPNPDev * device; for(device = devlist; device; device = device->pNext) { printf(" desc: %s\n st: %s\n\n", device->descURL, device->st); } 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) { // 4/16/2012 Why was I doing this? Just to read my external port? That shouldn't be necessary /* SystemAddress serverAddress=SelectAmongConnectedSystems(rakPeer, "NatTypeDetectionServer"); if (serverAddress==SLNet::UNASSIGNED_SYSTEM_ADDRESS) { serverAddress=ConnectBlocking(rakPeer, "NatTypeDetectionServer", DEFAULT_SERVER_ADDRESS, DEFAULT_SERVER_PORT); if (serverAddress==SLNet::UNASSIGNED_SYSTEM_ADDRESS) { printf("Failed to connect to a server.\n"); sampleResult=FAILED; return; } } char iport[32]; Itoa(sockets[0]->boundAddress.GetPort(),iport,10); char eport[32]; Itoa(rakPeer->GetExternalID(serverAddress).GetPort(),eport,10); */ // Use same external and internal ports DataStructures::List sockets; rakPeer->GetSockets(sockets); char iport[32]; Itoa(sockets[0]->GetBoundAddress().GetPort(),iport,10); char eport[32]; strcpy_s(eport, iport); // Version 1.5 // int r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, // eport, iport, lanaddr, 0, "UDP", 0); // Version miniupnpc-1.6.20120410 int r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, eport, iport, lanaddr, 0, "UDP", 0, "0"); if(r!=UPNPCOMMAND_SUCCESS) printf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", eport, iport, lanaddr, r, strupnperror(r)); char intPort[6]; char intClient[16]; // Version 1.5 // r = UPNP_GetSpecificPortMappingEntry(urls.controlURL, // data.first.servicetype, // eport, "UDP", // intClient, intPort); // Version miniupnpc-1.6.20120410 char desc[128]; char enabled[128]; char leaseDuration[128]; r = UPNP_GetSpecificPortMappingEntry(urls.controlURL, data.first.servicetype, eport, "UDP", intClient, intPort, desc, enabled, leaseDuration); if(r!=UPNPCOMMAND_SUCCESS) { printf("GetSpecificPortMappingEntry() failed with code %d (%s)\n", r, strupnperror(r)); sampleResult=FAILED; } else sampleResult=SUCCEEDED; } else sampleResult=FAILED; } else sampleResult=FAILED; } virtual void ProcessPacket(Packet *packet) { // unused parameters (void)packet; } virtual void Update(SLNet::RakPeerInterface *rakPeer) { // unused parameters (void)rakPeer; if (sampleResult==FAILED) return; } virtual void Shutdown(SLNet::RakPeerInterface *rakPeer) { // unused parameters (void)rakPeer; } }; struct NatTypeDetectionFramework : public SampleFramework { // Set to FAILED to skip this test NatTypeDetectionFramework() { sampleResult=SUPPORT_NAT_TYPE_DETECTION; ntdc=0;} virtual const char * QueryName(void) {return "NatTypeDetectionFramework";} virtual bool QueryRequiresServer(void) {return true;} virtual const char * QueryFunction(void) {return "Determines router type to avoid NAT punch attempts that cannot\nsucceed.";} virtual const char * QuerySuccess(void) {return "If our NAT type is Symmetric, we can skip NAT punch to other symmetric NATs.";} virtual bool QueryQuitOnSuccess(void) {return false;} virtual void Init(SLNet::RakPeerInterface *rakPeer) { if (sampleResult==FAILED) return; SystemAddress serverAddress=SelectAmongConnectedSystems(rakPeer, "NatTypeDetectionServer"); if (serverAddress== SLNet::UNASSIGNED_SYSTEM_ADDRESS) { serverAddress=ConnectBlocking(rakPeer, "NatTypeDetectionServer", DEFAULT_SERVER_ADDRESS, DEFAULT_SERVER_PORT); if (serverAddress== SLNet::UNASSIGNED_SYSTEM_ADDRESS) { printf("Failed to connect to a server.\n"); sampleResult=FAILED; return; } } ntdc = new NatTypeDetectionClient; rakPeer->AttachPlugin(ntdc); ntdc->DetectNATType(serverAddress); timeout= SLNet::GetTimeMS() + 5000; } virtual void ProcessPacket(Packet *packet) { if (packet->data[0]==ID_NAT_TYPE_DETECTION_RESULT) { SLNet::NATTypeDetectionResult r = (SLNet::NATTypeDetectionResult) packet->data[1]; printf("NAT Type is %s (%s)\n", NATTypeDetectionResultToString(r), NATTypeDetectionResultToStringFriendly(r)); printf("Using NATPunchthrough can connect to systems using:\n"); for (int i=0; i < (int)SLNet::NAT_TYPE_COUNT; i++) { if (CanConnect(r,(SLNet::NATTypeDetectionResult)i)) { if (i!=0) printf(", "); printf("%s", NATTypeDetectionResultToString((SLNet::NATTypeDetectionResult)i)); } } printf("\n"); if (r== SLNet::NAT_TYPE_PORT_RESTRICTED || r== SLNet::NAT_TYPE_SYMMETRIC) { // For UPNP, see Samples\UDPProxy printf("Note: Your router must support UPNP or have the user manually forward ports.\n"); printf("Otherwise NATPunchthrough may not always succeed.\n"); } sampleResult=SUCCEEDED; } } virtual void Update(SLNet::RakPeerInterface *rakPeer) { // unused parameters (void)rakPeer; if (sampleResult==FAILED) return; if (sampleResult==PENDING && SLNet::GetTimeMS()>timeout) { printf("No response from the server, probably not running NatTypeDetectionServer plugin.\n"); sampleResult=FAILED; } } virtual void Shutdown(SLNet::RakPeerInterface *rakPeer) { // unused parameters (void)rakPeer; delete ntdc; ntdc=0; } NatTypeDetectionClient *ntdc; SLNet::TimeMS timeout; }; struct NatPunchthoughClientFramework : public SampleFramework, public NatPunchthroughDebugInterface_Printf { SystemAddress serverAddress; // Set to FAILED to skip this test NatPunchthoughClientFramework() { sampleResult=SUPPORT_NAT_PUNCHTHROUGH; npClient=0;} virtual const char * QueryName(void) {return "NatPunchthoughClientFramework";} virtual bool QueryRequiresServer(void) {return true;} virtual const char * QueryFunction(void) {return "Causes two systems to try to connect to each other at the same\ntime, to get through routers.";} virtual const char * QuerySuccess(void) {return "We can now communicate with the other system, including connecting.";} virtual bool QueryQuitOnSuccess(void) {return true;} virtual void Init(SLNet::RakPeerInterface *rakPeer) { if (sampleResult==FAILED) return; serverAddress=SelectAmongConnectedSystems(rakPeer, "NatPunchthroughServer"); if (serverAddress== SLNet::UNASSIGNED_SYSTEM_ADDRESS) { serverAddress=ConnectBlocking(rakPeer, "NatPunchthroughServer", DEFAULT_SERVER_ADDRESS, DEFAULT_SERVER_PORT); if (serverAddress== SLNet::UNASSIGNED_SYSTEM_ADDRESS) { printf("Failed to connect to a server.\n"); sampleResult=FAILED; return; } } npClient = new NatPunchthroughClient; npClient->SetDebugInterface(this); rakPeer->AttachPlugin(npClient); char guid[128]; printf("Enter RakNetGuid of the remote system, which should have already connected\nto the server.\nOr press enter to just listen.\n"); Gets(guid,sizeof(guid)); if (guid[0]) { RakNetGUID remoteSystemGuid; remoteSystemGuid.FromString(guid); npClient->OpenNAT(remoteSystemGuid, serverAddress); isListening=false; timeout= SLNet::GetTimeMS() + 10000; } else { printf("Listening\n"); printf("My GUID is %s\n", rakPeer->GetMyGUID().ToString()); isListening=true; // Find the stride of our router in advance npClient->FindRouterPortStride(serverAddress); } } virtual void ProcessPacket(Packet *packet) { if ( packet->data[0]==ID_NAT_TARGET_NOT_CONNECTED || packet->data[0]==ID_NAT_TARGET_UNRESPONSIVE || packet->data[0]==ID_NAT_CONNECTION_TO_TARGET_LOST || packet->data[0]==ID_NAT_PUNCHTHROUGH_FAILED ) { RakNetGUID guid; if (packet->data[0]==ID_NAT_PUNCHTHROUGH_FAILED) { guid=packet->guid; } else { SLNet::BitStream bs(packet->data,packet->length,false); bs.IgnoreBytes(1); SLNET_VERIFY(bs.Read(guid)); } switch (packet->data[0]) { case ID_NAT_TARGET_NOT_CONNECTED: printf("Failed: ID_NAT_TARGET_NOT_CONNECTED\n"); break; case ID_NAT_TARGET_UNRESPONSIVE: printf("Failed: ID_NAT_TARGET_UNRESPONSIVE\n"); break; case ID_NAT_CONNECTION_TO_TARGET_LOST: printf("Failed: ID_NAT_CONNECTION_TO_TARGET_LOST\n"); break; case ID_NAT_PUNCHTHROUGH_FAILED: printf("Failed: ID_NAT_PUNCHTHROUGH_FAILED\n"); break; } sampleResult=FAILED; return; } else if (packet->data[0]==ID_NAT_PUNCHTHROUGH_SUCCEEDED) { unsigned char weAreTheSender = packet->data[1]; if (weAreTheSender) printf("NAT punch success to remote system %s.\n", packet->systemAddress.ToString(true)); else printf("NAT punch success from remote system %s.\n", packet->systemAddress.ToString(true)); char guid[128]; printf("Enter RakNetGuid of the remote system, which should have already connected.\nOr press enter to quit.\n"); Gets(guid,sizeof(guid)); if (guid[0]) { RakNetGUID remoteSystemGuid; remoteSystemGuid.FromString(guid); npClient->OpenNAT(remoteSystemGuid, serverAddress); timeout= SLNet::GetTimeMS() + 10000; } else { sampleResult=SUCCEEDED; } } } virtual void Update(SLNet::RakPeerInterface *rakPeer) { // unused parameters (void)rakPeer; if (sampleResult==FAILED) return; if (sampleResult==PENDING && SLNet::GetTimeMS()>timeout && !isListening) { printf("No response from the server, probably not running NatPunchthroughServer plugin.\n"); sampleResult=FAILED; } } virtual void Shutdown(SLNet::RakPeerInterface *rakPeer) { // unused parameters (void)rakPeer; delete npClient; npClient=0; } NatPunchthroughClient *npClient; SLNet::TimeMS timeout; bool isListening; }; struct Router2Framework : public SampleFramework { // Set to FAILED to skip this test Router2Framework() { sampleResult=SUPPORT_ROUTER2; router2=0;} virtual const char * QueryName(void) {return "Router2Framework";} virtual bool QueryRequiresServer(void) {return false;} virtual const char * QueryFunction(void) {return "Connect to a peer we cannot directly connect to using the\nbandwidth of a shared peer.";} virtual const char * QuerySuccess(void) {return "Router2 assumes we will now connect to the other system.";} virtual bool QueryQuitOnSuccess(void) {return true;} virtual void Init(SLNet::RakPeerInterface *rakPeer) { if (sampleResult==FAILED) return; printf("Given your application's bandwidth, how much traffic can be forwarded through a single peer?\nIf you use more than half the available bandwidth, then this plugin won't work for you.\n");; char supportedStr[64]; do { printf("Enter a number greater than or equal to 0: "); Gets(supportedStr,sizeof(supportedStr)); } while (supportedStr[0]==0); int supported=atoi(supportedStr); if (supported<=0) { printf("Aborting Router2\n"); sampleResult=FAILED; return; } SystemAddress peerAddress = SelectAmongConnectedSystems(rakPeer, "shared peer"); if (peerAddress== SLNet::UNASSIGNED_SYSTEM_ADDRESS) { peerAddress=ConnectBlocking(rakPeer, "shared peer", "", RAKPEER_PORT_STR); if (peerAddress== SLNet::UNASSIGNED_SYSTEM_ADDRESS) { printf("Failed to connect to a shared peer.\n"); sampleResult=FAILED; return; } } char guid[64]; printf("Destination system must be connected to the shared peer.\n"); do { printf("Enter RakNetGUID of destination system: "); Gets(guid,sizeof(guid)); } while (guid[0]==0); RakNetGUID endpointGuid; endpointGuid.FromString(guid); router2 = new Router2; rakPeer->AttachPlugin(router2); router2->EstablishRouting(endpointGuid); timeout= SLNet::GetTimeMS() + 5000; } virtual void ProcessPacket(Packet *packet) { // unused parameters (void)packet; } virtual void Update(SLNet::RakPeerInterface *rakPeer) { // unused parameters (void)rakPeer; if (sampleResult==FAILED) return; if (sampleResult==PENDING && SLNet::GetTimeMS()>timeout) { printf("No response from any system, probably not running Router2 plugin.\n"); sampleResult=FAILED; } } virtual void Shutdown(SLNet::RakPeerInterface *rakPeer) { // unused parameters (void)rakPeer; delete router2; router2=0; } Router2 *router2; SLNet::TimeMS timeout; }; struct UDPProxyClientFramework : public SampleFramework, public UDPProxyClientResultHandler { // Set to FAILED to skip this test UDPProxyClientFramework() { sampleResult=SUPPORT_UDP_PROXY; udpProxy=0;} virtual const char * QueryName(void) {return "UDPProxyClientFramework";} virtual bool QueryRequiresServer(void) {return true;} virtual const char * QueryFunction(void) {return "Connect to a peer using a shared server connection.";} virtual const char * QuerySuccess(void) {return "We can now communicate with the other system, including connecting, within 5 seconds.";} virtual bool QueryQuitOnSuccess(void) {return false;} virtual void Init(SLNet::RakPeerInterface *rakPeer) { if (sampleResult==FAILED) return; SystemAddress serverAddress=SelectAmongConnectedSystems(rakPeer, "UDPProxyCoordinator"); if (serverAddress== SLNet::UNASSIGNED_SYSTEM_ADDRESS) { serverAddress=ConnectBlocking(rakPeer, "UDPProxyCoordinator", DEFAULT_SERVER_ADDRESS, DEFAULT_SERVER_PORT); if (serverAddress== SLNet::UNASSIGNED_SYSTEM_ADDRESS) { printf("Failed to connect to a server.\n"); sampleResult=FAILED; return; } } udpProxy = new UDPProxyClient; rakPeer->AttachPlugin(udpProxy); udpProxy->SetResultHandler(this); char guid[128]; printf("Enter RakNetGuid of the remote system, which should have already connected\nto the server.\nOr press enter to just listen.\n"); Gets(guid,sizeof(guid)); RakNetGUID targetGuid; targetGuid.FromString(guid); if (guid[0]) { RakNetGUID remoteSystemGuid; remoteSystemGuid.FromString(guid); udpProxy->RequestForwarding(serverAddress, UNASSIGNED_SYSTEM_ADDRESS, targetGuid, UDP_FORWARDER_MAXIMUM_TIMEOUT, 0); isListening=false; } else { printf("Listening\n"); printf("My GUID is %s\n", rakPeer->GetGuidFromSystemAddress(UNASSIGNED_SYSTEM_ADDRESS).ToString()); isListening=true; } timeout= SLNet::GetTimeMS() + 5000; } virtual void ProcessPacket(Packet *packet) { // unused parameters (void)packet; } virtual void Update(SLNet::RakPeerInterface *rakPeer) { // unused parameters (void)rakPeer; if (sampleResult==FAILED) return; if (sampleResult==PENDING && SLNet::GetTimeMS()>timeout && !isListening) { printf("No response from the server, probably not running UDPProxyCoordinator plugin.\n"); sampleResult=FAILED; } } virtual void Shutdown(SLNet::RakPeerInterface *rakPeer) { // unused parameters (void)rakPeer; delete udpProxy; udpProxy=0; } virtual void OnForwardingSuccess(const char *proxyIPAddress, unsigned short proxyPort, SystemAddress proxyCoordinator, SystemAddress sourceAddress, SystemAddress targetAddress, RakNetGUID targetGuid, SLNet::UDPProxyClient *proxyClientPlugin) { // unused parameters (void)proxyCoordinator; (void)sourceAddress; (void)targetGuid; printf("Datagrams forwarded by proxy %s:%i to target %s.\n", proxyIPAddress, proxyPort, targetAddress.ToString(false)); printf("Connecting to proxy, which will be received by target.\n"); SLNET_VERIFY(proxyClientPlugin->GetRakPeerInterface()->Connect(proxyIPAddress, proxyPort, 0, 0) == CONNECTION_ATTEMPT_STARTED); sampleResult=SUCCEEDED; } virtual void OnForwardingNotification(const char *proxyIPAddress, unsigned short proxyPort, SystemAddress proxyCoordinator, SystemAddress sourceAddress, SystemAddress targetAddress, RakNetGUID targetGuid, SLNet::UDPProxyClient *proxyClientPlugin) { // unused parameters (void)proxyCoordinator; (void)targetAddress; (void)targetGuid; (void)proxyClientPlugin; printf("Source %s has setup forwarding to us through proxy %s:%i.\n", sourceAddress.ToString(false), proxyIPAddress, proxyPort); sampleResult=SUCCEEDED; } virtual void OnNoServersOnline(SystemAddress proxyCoordinator, SystemAddress sourceAddress, SystemAddress targetAddress, RakNetGUID targetGuid, SLNet::UDPProxyClient *proxyClientPlugin) { // unused parameters (void)proxyCoordinator; (void)sourceAddress; (void)targetAddress; (void)targetGuid; (void)proxyClientPlugin; printf("Failure: No servers logged into coordinator.\n"); sampleResult=FAILED; } virtual void OnRecipientNotConnected(SystemAddress proxyCoordinator, SystemAddress sourceAddress, SystemAddress targetAddress, RakNetGUID targetGuid, SLNet::UDPProxyClient *proxyClientPlugin) { // unused parameters (void)proxyCoordinator; (void)sourceAddress; (void)targetAddress; (void)targetGuid; (void)proxyClientPlugin; printf("Failure: Recipient not connected to coordinator.\n"); sampleResult=FAILED; } virtual void OnAllServersBusy(SystemAddress proxyCoordinator, SystemAddress sourceAddress, SystemAddress targetAddress, RakNetGUID targetGuid, SLNet::UDPProxyClient *proxyClientPlugin) { // unused parameters (void)proxyCoordinator; (void)sourceAddress; (void)targetAddress; (void)targetGuid; (void)proxyClientPlugin; printf("Failure: No servers have available forwarding ports.\n"); sampleResult=FAILED; } virtual void OnForwardingInProgress(const char *proxyIPAddress, unsigned short proxyPort, SystemAddress proxyCoordinator, SystemAddress sourceAddress, SystemAddress targetAddress, RakNetGUID targetGuid, SLNet::UDPProxyClient *proxyClientPlugin) { // unused parameters (void)proxyIPAddress; (void)proxyPort; (void)proxyCoordinator; (void)sourceAddress; (void)targetAddress; (void)targetGuid; (void)proxyClientPlugin; printf("Notification: Forwarding already in progress.\n"); } UDPProxyClient *udpProxy; SLNet::TimeMS timeout; bool isListening; }; void PrintPacketMessages(Packet *packet, RakPeerInterface *rakPeer) { switch (packet->data[0]) { case ID_DISCONNECTION_NOTIFICATION: // Connection lost normally printf("ID_DISCONNECTION_NOTIFICATION\n"); break; case ID_NEW_INCOMING_CONNECTION: printf("ID_NEW_INCOMING_CONNECTION\n"); break; case ID_ALREADY_CONNECTED: // Connection lost normally printf("ID_ALREADY_CONNECTED\n"); break; case ID_INCOMPATIBLE_PROTOCOL_VERSION: printf("ID_INCOMPATIBLE_PROTOCOL_VERSION\n"); break; case ID_REMOTE_DISCONNECTION_NOTIFICATION: // Server telling the clients of another client disconnecting gracefully. You can manually broadcast this in a peer to peer enviroment if you want. printf("ID_REMOTE_DISCONNECTION_NOTIFICATION\n"); break; case ID_REMOTE_CONNECTION_LOST: // Server telling the clients of another client disconnecting forcefully. You can manually broadcast this in a peer to peer enviroment if you want. printf("ID_REMOTE_CONNECTION_LOST\n"); break; case ID_REMOTE_NEW_INCOMING_CONNECTION: // Server telling the clients of another client connecting. You can manually broadcast this in a peer to peer enviroment if you want. printf("ID_REMOTE_NEW_INCOMING_CONNECTION\n"); break; case ID_CONNECTION_BANNED: // Banned from this server printf("We are banned from this server.\n"); break; case ID_CONNECTION_ATTEMPT_FAILED: printf("Connection attempt failed\n"); break; case ID_NO_FREE_INCOMING_CONNECTIONS: printf("ID_NO_FREE_INCOMING_CONNECTIONS\n"); break; case ID_INVALID_PASSWORD: printf("ID_INVALID_PASSWORD\n"); break; case ID_CONNECTION_LOST: printf("ID_CONNECTION_LOST from %s\n", packet->systemAddress.ToString(true)); break; case ID_CONNECTION_REQUEST_ACCEPTED: // This tells the client they have connected printf("ID_CONNECTION_REQUEST_ACCEPTED to %s with GUID %s\n", packet->systemAddress.ToString(true), packet->guid.ToString()); printf("My external address is %s\n", rakPeer->GetExternalID(packet->systemAddress).ToString(true)); break; } } enum FeatureList { _UPNPFramework, _NatTypeDetectionFramework, _NatPunchthoughFramework, _Router2Framework, _UDPProxyClientFramework, FEATURE_LIST_COUNT }; int main(void) { SLNet::RakPeerInterface *rakPeer= SLNet::RakPeerInterface::GetInstance(); printf("Enter local port, or press enter for default: "); char buff[64]; Gets(buff,sizeof(buff)); unsigned short port = DEFAULT_RAKPEER_PORT; if (buff[0]!=0) { const int intLocalPort = atoi(buff); if ((intLocalPort < 0) || (intLocalPort > std::numeric_limits::max())) { printf("Specified local port %d is outside valid bounds [0, %u]", intLocalPort, std::numeric_limits::max()); return 2; } port = static_cast(intLocalPort); } SLNet::SocketDescriptor sd(port,0); if (rakPeer->Startup(32,&sd,1)!= SLNet::RAKNET_STARTED) { printf("Failed to start rakPeer! Quitting\n"); SLNet::RakPeerInterface::DestroyInstance(rakPeer); _getch(); return 1; } rakPeer->SetMaximumIncomingConnections(32); SampleFramework *samples[FEATURE_LIST_COUNT]; unsigned int i=0; samples[i++] = new UPNPFramework; samples[i++] = new NatTypeDetectionFramework; samples[i++] = new NatPunchthoughClientFramework; samples[i++] = new Router2Framework; samples[i++] = new UDPProxyClientFramework; assert(i==FEATURE_LIST_COUNT); bool isFirstPrint=true; for (i=0; i < FEATURE_LIST_COUNT; i++) { if (isFirstPrint) { printf("NAT traversal client\nSupported operations:\n"); isFirstPrint=false; } printf("\n%s\nRequires server: %s\nDescription: %s\n", samples[i]->QueryName(), samples[i]->QueryRequiresServer()==1 ? "Yes" : "No", samples[i]->QueryFunction()); } printf("\nDo you have a server running the NATCompleteServer project? (y/n): "); int responseLetter=_getche(); bool hasServer=responseLetter=='y' || responseLetter=='Y' || responseLetter==' '; printf("\n"); if (!hasServer) printf("Note: Only UPNP and Router2 are supported without a server\nYou may want to consider using the Lobby2/Steam project. They host the\nservers for you.\n\n"); FeatureList currentStage=_UPNPFramework; if (!hasServer) { while (samples[(int) currentStage]->QueryRequiresServer()) { printf("No server: Skipping %s\n", samples[(int) currentStage]->QueryName()); int stageInt = (int) currentStage; stageInt++; currentStage=(FeatureList)stageInt; if (currentStage==FEATURE_LIST_COUNT) { printf("Connectivity not possible. Exiting\n"); _getch(); return 1; } } } bool running = true; while(running) { printf("Executing %s\n", samples[(int) currentStage]->QueryName()); samples[(int) currentStage]->Init(rakPeer); bool thisSampleDone = false; for(;;) { samples[(int) currentStage]->Update(rakPeer); SLNet::Packet *packet; for (packet=rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet=rakPeer->Receive()) { for (i=0; i < FEATURE_LIST_COUNT; i++) { samples[i]->ProcessPacket(packet); } PrintPacketMessages(packet, rakPeer); } if (samples[(int) currentStage]->sampleResult==FAILED || samples[(int) currentStage]->sampleResult==SUCCEEDED) { printf("\n"); thisSampleDone=true; if (samples[(int) currentStage]->sampleResult==FAILED) { printf("Failed %s\n", samples[(int) currentStage]->QueryName()); int stageInt = (int) currentStage; stageInt++; currentStage=(FeatureList)stageInt; if (currentStage==FEATURE_LIST_COUNT) { printf("Connectivity not possible. Exiting\n"); rakPeer->Shutdown(100); SLNet::RakPeerInterface::DestroyInstance(rakPeer); running = false; break; } else { printf("Proceeding to next stage.\n"); break; } } else { printf("Passed %s\n", samples[(int) currentStage]->QueryName()); if (samples[(int) currentStage]->QueryQuitOnSuccess()) { printf("Press any key to quit.\n"); while (!_kbhit()) { for (packet=rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet=rakPeer->Receive()) { for (i=0; i < FEATURE_LIST_COUNT; i++) { samples[i]->ProcessPacket(packet); } PrintPacketMessages(packet, rakPeer); } RakSleep(30); } rakPeer->Shutdown(100); SLNet::RakPeerInterface::DestroyInstance(rakPeer); printf("Press enter to quit.\n"); char temp[32]; Gets(temp,sizeof(temp)); running = false; break; } printf("Proceeding to next stage.\n"); int stageInt = (int) currentStage; stageInt++; if (stageIntReceive(); packet; rakPeer->DeallocatePacket(packet), packet=rakPeer->Receive()) { for (i=0; i < FEATURE_LIST_COUNT; i++) { samples[i]->ProcessPacket(packet); } PrintPacketMessages(packet, rakPeer); } RakSleep(30); } rakPeer->Shutdown(100); SLNet::RakPeerInterface::DestroyInstance(rakPeer); running = false; break; } break; } } RakSleep(30); } } _getch(); return 1; }