709 lines
21 KiB
C++
709 lines
21 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-2018, 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/UDPProxyServer.h"
|
|
#include "slikenet/UDPProxyCoordinator.h"
|
|
#include "slikenet/NatPunchthroughServer.h"
|
|
#include "slikenet/NatTypeDetectionServer.h"
|
|
#include "slikenet/SocketLayer.h"
|
|
#include "slikenet/Getche.h"
|
|
#include "slikenet/Gets.h"
|
|
#include "CloudServerHelper.h"
|
|
#include "slikenet/CloudClient.h"
|
|
#include "slikenet/statistics.h"
|
|
#include "slikenet/RelayPlugin.h"
|
|
#include "slikenet/linux_adapter.h"
|
|
#include "slikenet/osx_adapter.h"
|
|
|
|
//#define VERBOSE_LOGGING
|
|
|
|
using namespace SLNet;
|
|
|
|
enum FeatureSupport
|
|
{
|
|
SUPPORTED,
|
|
UNSUPPORTED,
|
|
QUERY
|
|
};
|
|
|
|
enum FeatureList
|
|
{
|
|
NAT_TYPE_DETECTION_SERVER,
|
|
NAT_PUNCHTHROUGH_SERVER,
|
|
RELAY_PLUGIN,
|
|
UDP_PROXY_COORDINATOR,
|
|
UDP_PROXY_SERVER,
|
|
CLOUD_SERVER,
|
|
FEATURE_LIST_COUNT,
|
|
};
|
|
|
|
static unsigned short DEFAULT_RAKPEER_PORT=61111;
|
|
|
|
#define NatTypeDetectionServerFramework_Supported QUERY
|
|
#define NatPunchthroughServerFramework_Supported QUERY
|
|
#define RelayPlugin_Supported QUERY
|
|
#define UDPProxyCoordinatorFramework_Supported UNSUPPORTED
|
|
#define UDPProxyServerFramework_Supported UNSUPPORTED
|
|
#define CloudServerFramework_Supported QUERY
|
|
|
|
struct SampleFramework
|
|
{
|
|
virtual const char * QueryName(void)=0;
|
|
virtual const char * QueryRequirements(void)=0;
|
|
virtual const char * QueryFunction(void)=0;
|
|
virtual void Init(SLNet::RakPeerInterface *rakPeer)=0;
|
|
virtual void ProcessPacket(SLNet::RakPeerInterface *rakPeer, Packet *packet)=0;
|
|
virtual void Shutdown(SLNet::RakPeerInterface *rakPeer)=0;
|
|
|
|
FeatureSupport isSupported;
|
|
};
|
|
|
|
struct NatTypeDetectionServerFramework : public SampleFramework
|
|
{
|
|
NatTypeDetectionServerFramework() {isSupported=NatTypeDetectionServerFramework_Supported; ntds=0;}
|
|
virtual const char * QueryName(void) {return "NatTypeDetectionServer";}
|
|
virtual const char * QueryRequirements(void) {return "Requires 4 IP addresses";}
|
|
virtual const char * QueryFunction(void) {return "Determines router type to filter by connectable systems.\nOne instance needed, multiple instances may exist to spread workload.";}
|
|
virtual void Init(SLNet::RakPeerInterface *rakPeer)
|
|
{
|
|
if (isSupported==SUPPORTED)
|
|
{
|
|
ntds = new NatTypeDetectionServer;
|
|
rakPeer->AttachPlugin(ntds);
|
|
|
|
if (rakPeer->GetNumberOfAddresses() < 4)
|
|
{
|
|
printf("Failed. Not enough IP addresses to bind to.\n");
|
|
rakPeer->DetachPlugin(ntds);
|
|
delete ntds;
|
|
ntds=0;
|
|
isSupported=UNSUPPORTED;
|
|
return;
|
|
}
|
|
ntds->Startup(rakPeer->GetLocalIP(1), rakPeer->GetLocalIP(2), rakPeer->GetLocalIP(3));
|
|
}
|
|
}
|
|
virtual void ProcessPacket(SLNet::RakPeerInterface *rakPeer, Packet *packet)
|
|
{
|
|
// unused parameters
|
|
(void)rakPeer;
|
|
(void)packet;
|
|
}
|
|
virtual void Shutdown(SLNet::RakPeerInterface *rakPeer)
|
|
{
|
|
if (ntds)
|
|
{
|
|
rakPeer->DetachPlugin(ntds);
|
|
delete ntds;
|
|
}
|
|
ntds=0;
|
|
}
|
|
|
|
NatTypeDetectionServer *ntds;
|
|
};
|
|
struct NatPunchthroughServerFramework : public SampleFramework, public NatPunchthroughServerDebugInterface_Printf
|
|
{
|
|
NatPunchthroughServerFramework() {isSupported=NatPunchthroughServerFramework_Supported; nps=0;}
|
|
virtual const char * QueryName(void) {return "NatPunchthroughServerFramework";}
|
|
virtual const char * QueryRequirements(void) {return "None";}
|
|
virtual const char * QueryFunction(void) {return "Coordinates NATPunchthroughClient.";}
|
|
virtual void Init(SLNet::RakPeerInterface *rakPeer)
|
|
{
|
|
if (isSupported==SUPPORTED)
|
|
{
|
|
nps = new NatPunchthroughServer;
|
|
rakPeer->AttachPlugin(nps);
|
|
#ifdef VERBOSE_LOGGING
|
|
nps->SetDebugInterface(this);
|
|
#endif
|
|
}
|
|
}
|
|
virtual void ProcessPacket(SLNet::RakPeerInterface *rakPeer, Packet *packet)
|
|
{
|
|
// unused parameters
|
|
(void)rakPeer;
|
|
(void)packet;
|
|
}
|
|
virtual void Shutdown(SLNet::RakPeerInterface *rakPeer)
|
|
{
|
|
if (nps)
|
|
{
|
|
rakPeer->DetachPlugin(nps);
|
|
delete nps;
|
|
}
|
|
nps=0;
|
|
}
|
|
|
|
NatPunchthroughServer *nps;
|
|
};
|
|
struct RelayPluginFramework : public SampleFramework
|
|
{
|
|
RelayPluginFramework() {relayPlugin=nullptr;isSupported=RelayPlugin_Supported;}
|
|
virtual const char * QueryName(void) {return "RelayPlugin";}
|
|
virtual const char * QueryRequirements(void) {return "None.";}
|
|
virtual const char * QueryFunction(void) {return "Relays messages between named connections.";}
|
|
virtual void Init(SLNet::RakPeerInterface *rakPeer)
|
|
{
|
|
if (isSupported==SUPPORTED)
|
|
{
|
|
relayPlugin = new RelayPlugin;
|
|
rakPeer->AttachPlugin(relayPlugin);
|
|
relayPlugin->SetAcceptAddParticipantRequests(true);
|
|
}
|
|
}
|
|
virtual void ProcessPacket(SLNet::RakPeerInterface *rakPeer, Packet *packet)
|
|
{
|
|
// unused parameters
|
|
(void)rakPeer;
|
|
(void)packet;
|
|
}
|
|
virtual void Shutdown(SLNet::RakPeerInterface *rakPeer)
|
|
{
|
|
if (relayPlugin)
|
|
{
|
|
rakPeer->DetachPlugin(relayPlugin);
|
|
delete relayPlugin;
|
|
relayPlugin=0;
|
|
}
|
|
}
|
|
|
|
RelayPlugin *relayPlugin;
|
|
};
|
|
struct UDPProxyCoordinatorFramework : public SampleFramework
|
|
{
|
|
UDPProxyCoordinatorFramework() {udppc=0; isSupported=UDPProxyCoordinatorFramework_Supported;}
|
|
virtual const char * QueryName(void) {return "UDPProxyCoordinator";}
|
|
virtual const char * QueryRequirements(void) {return "Bandwidth to handle a few hundred bytes per game session.";}
|
|
virtual const char * QueryFunction(void) {return "Coordinates UDPProxyClient to find available UDPProxyServer.\nExactly one instance required.";}
|
|
virtual void Init(SLNet::RakPeerInterface *rakPeer)
|
|
{
|
|
if (isSupported==SUPPORTED)
|
|
{
|
|
udppc = new UDPProxyCoordinator;
|
|
rakPeer->AttachPlugin(udppc);
|
|
|
|
char password[512];
|
|
printf("Create password for UDPProxyCoordinator: ");
|
|
Gets(password,sizeof(password));
|
|
if (password[0]==0)
|
|
{
|
|
password[0]='a';
|
|
password[1]=0;
|
|
}
|
|
udppc->SetRemoteLoginPassword(password);
|
|
}
|
|
}
|
|
virtual void ProcessPacket(SLNet::RakPeerInterface *rakPeer, Packet *packet)
|
|
{
|
|
// unused parameters
|
|
(void)rakPeer;
|
|
(void)packet;
|
|
}
|
|
virtual void Shutdown(SLNet::RakPeerInterface *rakPeer)
|
|
{
|
|
if (udppc)
|
|
{
|
|
rakPeer->DetachPlugin(udppc);
|
|
delete udppc;
|
|
udppc=0;
|
|
}
|
|
}
|
|
|
|
UDPProxyCoordinator *udppc;
|
|
};
|
|
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)
|
|
{
|
|
SystemAddress returnvalue = SLNet::UNASSIGNED_SYSTEM_ADDRESS;
|
|
char ipAddr[64];
|
|
printf("Enter IP of system %s is running on: ", hostName);
|
|
Gets(ipAddr,sizeof(ipAddr));
|
|
if (ipAddr[0]==0)
|
|
{
|
|
printf("Failed. Not connected to %s.\n", hostName);
|
|
return SLNet::UNASSIGNED_SYSTEM_ADDRESS;
|
|
}
|
|
char port[64];
|
|
printf("Enter port of system %s is running on: ", hostName);
|
|
Gets(port, sizeof(port));
|
|
if (port[0]==0)
|
|
{
|
|
printf("Failed. Not connected to %s.\n", hostName);
|
|
return SLNet::UNASSIGNED_SYSTEM_ADDRESS;
|
|
}
|
|
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;
|
|
|
|
rakPeer->DeallocatePacket(packet);
|
|
|
|
return returnvalue;
|
|
}
|
|
struct UDPProxyServerFramework : public SampleFramework, public UDPProxyServerResultHandler
|
|
{
|
|
UDPProxyServerFramework() {udpps=0; isSupported=UDPProxyServerFramework_Supported;}
|
|
virtual const char * QueryName(void) {return "UDPProxyServer";}
|
|
virtual const char * QueryRequirements(void) {return "Bandwidth to handle forwarded game traffic.";}
|
|
virtual const char * QueryFunction(void) {return "Allows game clients to forward network traffic transparently.\nOne or more instances required, can be added at runtime.";}
|
|
virtual void Init(SLNet::RakPeerInterface *rakPeer)
|
|
{
|
|
if (isSupported==SUPPORTED)
|
|
{
|
|
printf("Logging into UDPProxyCoordinator...\n");
|
|
SystemAddress coordinatorAddress=SelectAmongConnectedSystems(rakPeer, "UDPProxyCoordinator");
|
|
if (coordinatorAddress== SLNet::UNASSIGNED_SYSTEM_ADDRESS)
|
|
{
|
|
printf("Warning: RakPeer is not currently connected to any system.\nEnter option:\n(1). UDPProxyCoordinator is on localhost\n(2). Connect to a remote system\n(3). Fail.\nOption: ");
|
|
int ch=_getche();
|
|
printf("\n");
|
|
if (ch=='1' || ch==13) // 13 is just pressing return
|
|
{
|
|
coordinatorAddress=rakPeer->GetInternalID(UNASSIGNED_SYSTEM_ADDRESS,0);
|
|
}
|
|
else if (ch=='2')
|
|
{
|
|
coordinatorAddress=ConnectBlocking(rakPeer, "UDPProxyCoordinator");
|
|
if (coordinatorAddress== SLNet::UNASSIGNED_SYSTEM_ADDRESS)
|
|
{
|
|
printf("Failed to connect.\n");
|
|
isSupported=QUERY;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
printf("Failed. Not connected to UDPProxyCoordinator.\n");
|
|
isSupported=QUERY;
|
|
return;
|
|
}
|
|
}
|
|
|
|
char password[512];
|
|
printf("Enter password used with UDPProxyCoordinator: ");
|
|
Gets(password,sizeof(password));
|
|
if (password[0]==0)
|
|
{
|
|
password[0]='a';
|
|
password[1]=0;
|
|
}
|
|
|
|
udpps = new UDPProxyServer;
|
|
udpps->SetResultHandler(this);
|
|
rakPeer->AttachPlugin(udpps);
|
|
if (udpps->LoginToCoordinator(password, coordinatorAddress)==false)
|
|
{
|
|
printf("LoginToCoordinator call failed.\n");
|
|
isSupported=QUERY;
|
|
rakPeer->DetachPlugin(udpps);
|
|
delete udpps;
|
|
udpps=0;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
virtual void ProcessPacket(SLNet::RakPeerInterface *rakPeer, Packet *packet)
|
|
{
|
|
// unused parameters
|
|
(void)rakPeer;
|
|
(void)packet;
|
|
}
|
|
virtual void Shutdown(SLNet::RakPeerInterface *rakPeer)
|
|
{
|
|
if (udpps)
|
|
{
|
|
rakPeer->DetachPlugin(udpps);
|
|
delete udpps;
|
|
udpps=0;
|
|
}
|
|
}
|
|
|
|
virtual void OnLoginSuccess(SLNet::RakString usedPassword, SLNet::UDPProxyServer *proxyServerPlugin)
|
|
{
|
|
// unused parameters
|
|
(void)proxyServerPlugin;
|
|
|
|
printf("%s logged into UDPProxyCoordinator.\n", QueryName());
|
|
}
|
|
virtual void OnAlreadyLoggedIn(SLNet::RakString usedPassword, SLNet::UDPProxyServer *proxyServerPlugin)
|
|
{
|
|
// unused parameters
|
|
(void)proxyServerPlugin;
|
|
|
|
printf("%s already logged into UDPProxyCoordinator.\n", QueryName());
|
|
}
|
|
virtual void OnNoPasswordSet(SLNet::RakString usedPassword, SLNet::UDPProxyServer *proxyServerPlugin)
|
|
{
|
|
// unused parameters
|
|
(void)proxyServerPlugin;
|
|
|
|
printf("%s failed login to UDPProxyCoordinator. No password set.\n", QueryName());
|
|
isSupported=QUERY;
|
|
delete udpps;
|
|
udpps=0;
|
|
}
|
|
virtual void OnWrongPassword(SLNet::RakString usedPassword, SLNet::UDPProxyServer *proxyServerPlugin)
|
|
{
|
|
// unused parameters
|
|
(void)proxyServerPlugin;
|
|
|
|
printf("%s failed login to UDPProxyCoordinator. %s was the wrong password.\n", QueryName(), usedPassword.C_String());
|
|
isSupported=QUERY;
|
|
delete udpps;
|
|
udpps=0;
|
|
}
|
|
|
|
UDPProxyServer *udpps;
|
|
};
|
|
struct CloudServerFramework : public SampleFramework
|
|
{
|
|
CloudServerFramework() {cloudServer=nullptr;isSupported=CloudServerFramework_Supported;}
|
|
virtual const char * QueryName(void) {return "CloudServer";}
|
|
virtual const char * QueryRequirements(void) {return "None.";}
|
|
virtual const char * QueryFunction(void) {return "Single instance cloud server that maintains connection counts\nUseful as a directory server to find other client instances.";}
|
|
virtual void Init(SLNet::RakPeerInterface *rakPeer)
|
|
{
|
|
if (isSupported==SUPPORTED)
|
|
{
|
|
cloudServer = new CloudServer;
|
|
rakPeer->AttachPlugin(cloudServer);
|
|
cloudClient = new CloudClient;
|
|
rakPeer->AttachPlugin(cloudClient);
|
|
cloudServerHelperFilter = new CloudServerHelperFilter;
|
|
cloudServer->AddQueryFilter(cloudServerHelperFilter);
|
|
cloudServer->SetMaxUploadBytesPerClient(65535);
|
|
cloudServerHelper.OnConnectionCountChange(rakPeer, cloudClient);
|
|
}
|
|
}
|
|
virtual void ProcessPacket(SLNet::RakPeerInterface *rakPeer, Packet *packet)
|
|
{
|
|
if (isSupported!=SUPPORTED)
|
|
return;
|
|
|
|
switch (packet->data[0])
|
|
{
|
|
case ID_NEW_INCOMING_CONNECTION:
|
|
#ifdef VERBOSE_LOGGING
|
|
printf("Got connection to %s\n", packet->systemAddress.ToString(true));
|
|
#endif
|
|
cloudServerHelper.OnConnectionCountChange(rakPeer, cloudClient);
|
|
break;
|
|
case ID_CONNECTION_LOST:
|
|
case ID_DISCONNECTION_NOTIFICATION:
|
|
#ifdef VERBOSE_LOGGING
|
|
printf("Lost connection to %s\n", packet->systemAddress.ToString(true));
|
|
#endif
|
|
cloudServerHelper.OnConnectionCountChange(rakPeer, cloudClient);
|
|
break;
|
|
}
|
|
}
|
|
virtual void Shutdown(SLNet::RakPeerInterface *rakPeer)
|
|
{
|
|
if (cloudServer)
|
|
{
|
|
rakPeer->DetachPlugin(cloudServer);
|
|
delete cloudServer;
|
|
cloudServer=0;
|
|
rakPeer->DetachPlugin(cloudClient);
|
|
delete cloudClient;
|
|
cloudClient=0;
|
|
delete cloudServerHelperFilter;
|
|
cloudServerHelperFilter=0;
|
|
}
|
|
}
|
|
|
|
SLNet::CloudServer *cloudServer;
|
|
SLNet::CloudClient *cloudClient;
|
|
SLNet::CloudServerHelperFilter *cloudServerHelperFilter;
|
|
SLNet::CloudServerHelper cloudServerHelper;
|
|
};
|
|
int main(int argc, char **argv)
|
|
{
|
|
SLNet::RakPeerInterface *rakPeer= SLNet::RakPeerInterface::GetInstance();
|
|
SystemAddress ipList[ MAXIMUM_NUMBER_OF_INTERNAL_IDS ];
|
|
printf("IPs:\n");
|
|
unsigned int i;
|
|
for (i=0; i < MAXIMUM_NUMBER_OF_INTERNAL_IDS; i++) {
|
|
ipList[i]=rakPeer->GetLocalIP(i);
|
|
if (ipList[i]!=UNASSIGNED_SYSTEM_ADDRESS)
|
|
printf("%i. %s\n", i+1, ipList[i].ToString(false));
|
|
else
|
|
break;
|
|
}
|
|
|
|
if (i == 0 && argc <= 3) {
|
|
printf("Could not determine any local IP address.\n");
|
|
return 3;
|
|
}
|
|
|
|
// If RakPeer is started on 2 IP addresses, NATPunchthroughServer supports port stride detection, improving success rate
|
|
int sdLen=1;
|
|
SLNet::SocketDescriptor sd[2];
|
|
if (argc>1)
|
|
{
|
|
const int intPeerPort = atoi(argv[1]);
|
|
if ((intPeerPort < 0) || (intPeerPort > std::numeric_limits<unsigned short>::max())) {
|
|
printf("Specified peer port %d is outside valid bounds [0, %u]", intPeerPort, std::numeric_limits<unsigned short>::max());
|
|
return 2;
|
|
}
|
|
DEFAULT_RAKPEER_PORT = static_cast<unsigned short>(intPeerPort);
|
|
}
|
|
|
|
// set the first IP address
|
|
sd[0].port = DEFAULT_RAKPEER_PORT;
|
|
// #med - improve the logic here to simplify the handling...
|
|
if (argc > 2)
|
|
strcpy_s(sd[0].hostAddress, argv[2]);
|
|
|
|
// #high - improve determining the proper IP addresses
|
|
// - filter between IPv4/IPv6 and only use either of these
|
|
// - fallback to other IP addresses, if a given one failed to be bound
|
|
// allow enforcing single IP address mode by specifying second/third argument to the same IP address
|
|
if ((i >= 2 && argc <= 3) || (argc > 3)) {
|
|
const char *ipAddress1 = (argc > 2) ? argv[2] : ipList[0].ToString(false);
|
|
const char *ipAddress2 = (argc > 3) ? argv[3] : ipList[1].ToString(false);
|
|
strcpy_s(sd[0].hostAddress, ipAddress1);
|
|
sd[1].port = DEFAULT_RAKPEER_PORT+1;
|
|
strcpy_s(sd[1].hostAddress, ipAddress2);
|
|
printf("Dual IP address mode.\nFirst IP Address: '%s' (port: %u)\nSecond IP Address: '%s' (port: %u)\n", ipAddress1, sd[0].port, ipAddress2, sd[1].port);
|
|
sdLen = 2;
|
|
}
|
|
else {
|
|
printf("Single IP address mode.\nUsing port %i\n", sd[0].port);
|
|
}
|
|
|
|
const StartupResult success = rakPeer->Startup(8096, sd, sdLen);
|
|
if (success != SLNet::RAKNET_STARTED)
|
|
{
|
|
printf("Failed to start rakPeer! Quitting - error code: %d\n", success);
|
|
SLNet::RakPeerInterface::DestroyInstance(rakPeer);
|
|
return 1;
|
|
}
|
|
rakPeer->SetTimeoutTime(5000, UNASSIGNED_SYSTEM_ADDRESS);
|
|
printf("Started on %s\n\n", rakPeer->GetMyBoundAddress().ToString(true));
|
|
|
|
rakPeer->SetMaximumIncomingConnections(8096);
|
|
|
|
SampleFramework *samples[FEATURE_LIST_COUNT];
|
|
i=0;
|
|
samples[i++] = new NatTypeDetectionServerFramework;
|
|
samples[i++] = new NatPunchthroughServerFramework;
|
|
samples[i++] = new RelayPluginFramework;
|
|
samples[i++] = new UDPProxyCoordinatorFramework;
|
|
samples[i++] = new UDPProxyServerFramework;
|
|
samples[i++] = new CloudServerFramework;
|
|
assert(i==FEATURE_LIST_COUNT);
|
|
|
|
bool isFirstPrint=true;
|
|
for (i=0; i < FEATURE_LIST_COUNT; i++)
|
|
{
|
|
if (samples[i]->isSupported==QUERY)
|
|
{
|
|
if (isFirstPrint)
|
|
{
|
|
printf("NAT traversal server.\nSee http://www.dx.net/raknet_dx.php for discounted server hosting\nSelect which features to support.\n");
|
|
isFirstPrint=false;
|
|
}
|
|
printf("\n%s\nRequirements: %s\nDescription: %s\n", samples[i]->QueryName(), samples[i]->QueryRequirements(), samples[i]->QueryFunction());
|
|
printf("Support %s? (y/n): ", samples[i]->QueryName());
|
|
int supported=_getche();
|
|
if (supported=='y' || supported=='Y' || supported==13) // 13 is just pressing return
|
|
{
|
|
samples[i]->isSupported=SUPPORTED;
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
for (i=0; i < FEATURE_LIST_COUNT; i++)
|
|
{
|
|
if (samples[i]->isSupported==SUPPORTED)
|
|
{
|
|
printf("Starting %s...\n", samples[i]->QueryName());
|
|
samples[i]->Init(rakPeer);
|
|
if (samples[i]->isSupported!=SUPPORTED)
|
|
{
|
|
printf("Failed to start %s.", samples[i]->QueryName());
|
|
if (samples[i]->isSupported==QUERY)
|
|
{
|
|
printf(" Retry? (y/n): ");
|
|
int supported=_getche();
|
|
if (supported=='y' || supported=='Y')
|
|
{
|
|
samples[i]->isSupported=SUPPORTED;
|
|
i--;
|
|
}
|
|
}
|
|
else
|
|
printf("\n");
|
|
printf("\n");
|
|
}
|
|
else
|
|
printf("Success.\n\n");
|
|
}
|
|
}
|
|
|
|
bool anySupported=false;
|
|
for (i=0; i < FEATURE_LIST_COUNT; i++)
|
|
{
|
|
if (samples[i]->isSupported==SUPPORTED)
|
|
{
|
|
anySupported=true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (anySupported==false)
|
|
{
|
|
printf("No features supported! Quitting.\n");
|
|
rakPeer->Shutdown(100);
|
|
SLNet::RakPeerInterface::DestroyInstance(rakPeer);
|
|
return 1;
|
|
}
|
|
|
|
bool firstComma=true;
|
|
printf("Supported features: ");
|
|
for (i=0; i < FEATURE_LIST_COUNT; i++)
|
|
{
|
|
if (samples[i]->isSupported==SUPPORTED)
|
|
{
|
|
if (firstComma==false)
|
|
printf(", ");
|
|
else
|
|
firstComma=false;
|
|
printf("%s", samples[i]->QueryName());
|
|
}
|
|
}
|
|
|
|
printf("\nEntering update loop. Press 'q' to quit.\n");
|
|
|
|
SLNet::Packet *packet;
|
|
bool quit=false;
|
|
while (!quit)
|
|
{
|
|
for (packet=rakPeer->Receive(); packet; rakPeer->DeallocatePacket(packet), packet=rakPeer->Receive())
|
|
{
|
|
for (i=0; i < FEATURE_LIST_COUNT; i++)
|
|
{
|
|
samples[i]->ProcessPacket(rakPeer, packet);
|
|
}
|
|
}
|
|
|
|
if (_kbhit())
|
|
{
|
|
int ch = _getch();
|
|
if (ch=='q')
|
|
{
|
|
quit=true;
|
|
}
|
|
else if (ch==' ')
|
|
{
|
|
RakNetStatistics rns;
|
|
char message[2048];
|
|
bool hasStatistics = rakPeer->GetStatistics(0, &rns);
|
|
if (hasStatistics)
|
|
{
|
|
StatisticsToString(&rns, message, 2048, 2);
|
|
printf("SYSTEM 0:\n%s\n", message);
|
|
|
|
memset(&rns, 0, sizeof(RakNetStatistics));
|
|
rakPeer->GetStatistics(UNASSIGNED_SYSTEM_ADDRESS, &rns);
|
|
StatisticsToString(&rns, message, 2048, 2);
|
|
printf("STAT SUM:\n%s\n", message);
|
|
}
|
|
else
|
|
{
|
|
printf("No system 0\n");
|
|
}
|
|
|
|
DataStructures::List<SystemAddress> addresses;
|
|
DataStructures::List<RakNetGUID> guids;
|
|
rakPeer->GetSystemList(addresses, guids);
|
|
printf("%i systems connected\n", addresses.Size());
|
|
}
|
|
}
|
|
RakSleep(30);
|
|
}
|
|
|
|
printf("Quitting.\n");
|
|
for (i=0; i < FEATURE_LIST_COUNT; i++)
|
|
{
|
|
samples[i]->Shutdown(rakPeer);
|
|
}
|
|
rakPeer->Shutdown(100);
|
|
SLNet::RakPeerInterface::DestroyInstance(rakPeer);
|
|
return 0;
|
|
}
|
|
|