Files
2025-11-24 14:19:51 +05:30

1025 lines
32 KiB
C++

/*
* 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-2019, 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits> // 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<SystemAddress> addresses;
DataStructures::List<RakNetGUID> 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<size_t>(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<unsigned short>::max())) {
printf("Failed. Specified port %d is outside valid bounds [0, %u]", intPort, std::numeric_limits<unsigned short>::max());
return SLNet::UNASSIGNED_SYSTEM_ADDRESS;
}
if (rakPeer->Connect(ipAddr, static_cast<unsigned short>(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<RakNetSocket2* > 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==false)
{
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==false)
{
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<unsigned short>::max())) {
printf("Specified local port %d is outside valid bounds [0, %u]", intLocalPort, std::numeric_limits<unsigned short>::max());
return 2;
}
port = static_cast<unsigned short>(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==false)
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==false)
{
while (samples[(int) currentStage]->QueryRequiresServer()==true)
{
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 (stageInt<FEATURE_LIST_COUNT)
{
currentStage=(FeatureList)stageInt;
}
else
{
printf("Press any key to quit when done.\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);
running = false;
break;
}
break;
}
}
RakSleep(30);
}
}
_getch();
return 1;
}