386 lines
11 KiB
C++
386 lines
11 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/GetTime.h"
|
|
#include "slikenet/MessageIdentifiers.h"
|
|
#include "slikenet/BitStream.h"
|
|
#include <cstdio>
|
|
#include <memory.h>
|
|
#include <cstring>
|
|
#include <stdlib.h>
|
|
#include "slikenet/Rand.h"
|
|
#include "slikenet/statistics.h"
|
|
#include "slikenet/sleep.h"
|
|
#include "slikenet/memoryoverride.h"
|
|
#include <stdio.h>
|
|
#include <limits> // used for std::numeric_limits
|
|
#include "slikenet/Gets.h"
|
|
#include "slikenet/Kbhit.h"
|
|
#include "slikenet/linux_adapter.h"
|
|
#include "slikenet/osx_adapter.h"
|
|
|
|
using namespace SLNet;
|
|
|
|
#ifdef _WIN32
|
|
#include "slikenet/WindowsIncludes.h" // Sleep
|
|
#else
|
|
#include <unistd.h> // usleep
|
|
#endif
|
|
|
|
FILE *fp;
|
|
int memoryUsage=0;
|
|
void *LoggedMalloc(size_t size, const char *file, unsigned int line)
|
|
{
|
|
memoryUsage+=size;
|
|
if (fp)
|
|
fprintf(fp,"Alloc %s:%i %i bytes %i total\n", file,line,size,memoryUsage);
|
|
char *p = (char*) malloc(size+sizeof(size));
|
|
memcpy(p,&size,sizeof(size));
|
|
return p+sizeof(size);
|
|
}
|
|
void LoggedFree(void *p, const char *file, unsigned int line)
|
|
{
|
|
char *realP=(char*)p-sizeof(size_t);
|
|
size_t allocatedSize;
|
|
memcpy(&allocatedSize,realP,sizeof(size_t));
|
|
memoryUsage-=allocatedSize;
|
|
if (fp)
|
|
fprintf(fp,"Free %s:%i %i bytes %i total\n", file,line,allocatedSize,memoryUsage);
|
|
free(realP);
|
|
}
|
|
void* LoggedRealloc(void *p, size_t size, const char *file, unsigned int line)
|
|
{
|
|
char *realP=(char*)p-sizeof(size_t);
|
|
size_t allocatedSize;
|
|
memcpy(&allocatedSize,realP,sizeof(size_t));
|
|
memoryUsage-=allocatedSize;
|
|
memoryUsage+=size;
|
|
p = realloc(realP,size+sizeof(size));
|
|
memcpy(p,&size,sizeof(size));
|
|
if (fp)
|
|
fprintf(fp,"Realloc %s:%i %i to %i bytes %i total\n", file,line,allocatedSize,size,memoryUsage);
|
|
return (char*)p+sizeof(size);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
RakPeerInterface *sender, *receiver;
|
|
unsigned int packetNumber[32], receivedPacketNumber;
|
|
SLNet::Time receivedTime;
|
|
char str[256];
|
|
char ip[32];
|
|
// initialize to silence false-positive warning C4701 with VS2015+
|
|
SLNet::Time sendInterval = 0;
|
|
SLNet::Time nextSend, currentTime, quitTime;
|
|
unsigned short remotePort, localPort;
|
|
unsigned char streamNumber;
|
|
SLNet::BitStream bitStream;
|
|
SLNet::Packet *packet;
|
|
bool doSend=false;
|
|
|
|
for (int i=0; i < 32; i++)
|
|
packetNumber[i]=0;
|
|
|
|
printf("This project tests RakNet's reliable ordered sending system.\n");
|
|
printf("Difficulty: Beginner\n\n");
|
|
|
|
printf("Act as (s)ender or (r)eceiver?\n");
|
|
Gets(str, sizeof(str));
|
|
if (str[0]==0)
|
|
return 1;
|
|
|
|
if (argc==2)
|
|
{
|
|
fopen_s(&fp,argv[1],"wt");
|
|
SetMalloc_Ex(LoggedMalloc);
|
|
SetRealloc_Ex(LoggedRealloc);
|
|
SetFree_Ex(LoggedFree);
|
|
}
|
|
else
|
|
fp=0;
|
|
|
|
if (str[0]=='s' || str[0]=='S')
|
|
{
|
|
sender = SLNet::RakPeerInterface::GetInstance();
|
|
|
|
receiver = 0;
|
|
|
|
printf("Enter number of ms to pass between sends: ");
|
|
Gets(str, sizeof(str));
|
|
if (str[0]==0)
|
|
sendInterval=33;
|
|
else
|
|
sendInterval=atoi(str);
|
|
|
|
printf("Enter remote IP: ");
|
|
Gets(ip, sizeof(ip));
|
|
if (ip[0]==0)
|
|
strcpy_s(ip, "127.0.0.1");
|
|
// strcpy_s(ip, "natpunch.slikesoft.com");
|
|
|
|
printf("Enter remote port: ");
|
|
Gets(str, sizeof(str));
|
|
if (str[0]==0)
|
|
strcpy_s(str, "60000");
|
|
const int intRemotePort = atoi(str);
|
|
if ((intRemotePort < 0) || (intRemotePort > std::numeric_limits<unsigned short>::max())) {
|
|
printf("Specified remote port %d is outside valid bounds [0, %u]", intRemotePort, std::numeric_limits<unsigned short>::max());
|
|
return 2;
|
|
}
|
|
remotePort = static_cast<unsigned short>(intRemotePort);
|
|
|
|
printf("Enter local port: ");
|
|
Gets(str, sizeof(str));
|
|
if (str[0]==0)
|
|
strcpy_s(str, "0");
|
|
const int intLocalPort = atoi(str);
|
|
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 3;
|
|
}
|
|
localPort = static_cast<unsigned short>(intLocalPort);
|
|
|
|
|
|
printf("Connecting...\n");
|
|
SLNet::SocketDescriptor socketDescriptor(localPort,0);
|
|
sender->Startup(8, &socketDescriptor, 1);
|
|
// sender->ApplyNetworkSimulator(.2, 0, 0);
|
|
sender->Connect(ip, remotePort, 0, 0);
|
|
}
|
|
else
|
|
{
|
|
receiver = SLNet::RakPeerInterface::GetInstance();
|
|
// receiver->ApplyNetworkSimulator(.2, 0, 0);
|
|
sender=0;
|
|
|
|
printf("Enter local port: ");
|
|
Gets(str, sizeof(str));
|
|
if (str[0]==0)
|
|
strcpy_s(str, "60000");
|
|
const int intLocalPort = atoi(str);
|
|
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 3;
|
|
}
|
|
localPort = static_cast<unsigned short>(intLocalPort);
|
|
|
|
printf("Waiting for connections...\n");
|
|
SLNet::SocketDescriptor socketDescriptor(localPort,0);
|
|
receiver->Startup(8, &socketDescriptor, 1);
|
|
receiver->SetMaximumIncomingConnections(8);
|
|
}
|
|
|
|
seedMT(1);
|
|
|
|
printf("How long to run this test for, in seconds?\n");
|
|
Gets(str, sizeof(str));
|
|
if (str[0]==0)
|
|
strcpy_s(str, "12000");
|
|
|
|
currentTime = SLNet::GetTimeMS();
|
|
quitTime = atoi(str) * 1000 + currentTime;
|
|
|
|
nextSend=currentTime;
|
|
|
|
printf("Test running.\n");
|
|
|
|
//while (currentTime < quitTime)
|
|
for(;;)
|
|
{
|
|
#ifdef _WIN32
|
|
if (_kbhit())
|
|
{
|
|
int ch=_getch();
|
|
if (ch=='q')
|
|
break;
|
|
else if (ch==' ')
|
|
{
|
|
RakNetStatistics *rss;
|
|
char message[2048];
|
|
if (sender)
|
|
rss=sender->GetStatistics(sender->GetSystemAddressFromIndex(0));
|
|
else
|
|
rss=receiver->GetStatistics(receiver->GetSystemAddressFromIndex(0));
|
|
StatisticsToString(rss, message, 2048, 2);
|
|
printf("%s", message);
|
|
}
|
|
}
|
|
#endif
|
|
if (sender)
|
|
{
|
|
uint32_t msgNumber;
|
|
packet = sender->Receive();
|
|
while (packet)
|
|
{
|
|
// PARSE TYPES
|
|
switch(packet->data[0])
|
|
{
|
|
case ID_CONNECTION_REQUEST_ACCEPTED:
|
|
printf("ID_CONNECTION_REQUEST_ACCEPTED\n");
|
|
doSend=true;
|
|
nextSend=currentTime;
|
|
break;
|
|
case ID_NO_FREE_INCOMING_CONNECTIONS:
|
|
printf("ID_NO_FREE_INCOMING_CONNECTIONS\n");
|
|
break;
|
|
case ID_DISCONNECTION_NOTIFICATION:
|
|
printf("ID_DISCONNECTION_NOTIFICATION\n");
|
|
break;
|
|
case ID_CONNECTION_LOST:
|
|
printf("ID_CONNECTION_LOST\n");
|
|
break;
|
|
case ID_CONNECTION_ATTEMPT_FAILED:
|
|
printf("Connection attempt failed\n");
|
|
break;
|
|
case ID_SND_RECEIPT_ACKED:
|
|
memcpy(&msgNumber, packet->data+1, 4);
|
|
printf("Msg #%i was delivered.\n", msgNumber);
|
|
break;
|
|
case ID_SND_RECEIPT_LOSS:
|
|
memcpy(&msgNumber, packet->data+1, 4);
|
|
printf("Msg #%i was probably not delivered.\n", msgNumber);
|
|
break;
|
|
}
|
|
|
|
sender->DeallocatePacket(packet);
|
|
packet = sender->Receive();
|
|
}
|
|
|
|
char *type="UNDEFINED";
|
|
while (doSend && currentTime > nextSend)
|
|
{
|
|
streamNumber=0;
|
|
streamNumber = randomMT() % 4;
|
|
// Do the send
|
|
|
|
for (int i=0; i < 2; i++)
|
|
{
|
|
bitStream.Reset();
|
|
bitStream.Write((unsigned char) (ID_TIMESTAMP));
|
|
bitStream.Write(SLNet::GetTime());
|
|
bitStream.Write((unsigned char) (ID_USER_PACKET_ENUM+1));
|
|
bitStream.Write(packetNumber[streamNumber]);
|
|
packetNumber[streamNumber]++;
|
|
bitStream.Write(streamNumber);
|
|
|
|
PacketReliability reliability;
|
|
// #med - review --- was commented out in RakNet via if(0)
|
|
/*if (0 && (randomMT()%2)==0)
|
|
{
|
|
type="UNRELIABLE_SEQUENCED";
|
|
reliability=UNRELIABLE_SEQUENCED;
|
|
}
|
|
else
|
|
{*/
|
|
type="RELIABLE_ORDERED";
|
|
reliability=RELIABLE_ORDERED;
|
|
//}
|
|
|
|
int padLength;
|
|
padLength = (randomMT() % 25000) + 1;
|
|
bitStream.Write(reliability);
|
|
bitStream.PadWithZeroToByteLength(padLength);
|
|
|
|
if (sender->Send(&bitStream, HIGH_PRIORITY, reliability ,streamNumber, SLNet::UNASSIGNED_SYSTEM_ADDRESS, true)==0)
|
|
{
|
|
packetNumber[streamNumber]--;
|
|
}
|
|
}
|
|
|
|
// RakNetStatistics *rssSender;
|
|
//rssSender=sender->GetStatistics(sender->GetSystemAddressFromIndex(0));
|
|
|
|
printf("Snd: %i, %s, time %" PRINTF_64_BIT_MODIFIER "u, length %i\n", packetNumber[streamNumber]-1, type, currentTime, bitStream.GetNumberOfBytesUsed());
|
|
|
|
nextSend+=sendInterval;
|
|
|
|
// Test halting
|
|
// if (rand()%20==0)
|
|
// nextSend+=1000;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
packet = receiver->Receive();
|
|
while (packet)
|
|
{
|
|
switch(packet->data[0])
|
|
{
|
|
case ID_NEW_INCOMING_CONNECTION:
|
|
printf("ID_NEW_INCOMING_CONNECTION\n");
|
|
break;
|
|
case ID_DISCONNECTION_NOTIFICATION:
|
|
printf("ID_DISCONNECTION_NOTIFICATION\n");
|
|
break;
|
|
case ID_CONNECTION_LOST:
|
|
printf("ID_CONNECTION_LOST\n");
|
|
break;
|
|
case ID_TIMESTAMP:
|
|
bitStream.Reset();
|
|
bitStream.Write((char*)packet->data, packet->length);
|
|
bitStream.IgnoreBits(8); // Ignore ID_TIMESTAMP
|
|
bitStream.Read(receivedTime);
|
|
bitStream.IgnoreBits(8); // Ignore ID_USER_ENUM+1
|
|
bitStream.Read(receivedPacketNumber);
|
|
bitStream.Read(streamNumber);
|
|
PacketReliability reliability;
|
|
bitStream.Read(reliability);
|
|
char *type="UNDEFINED";
|
|
if (reliability==UNRELIABLE_SEQUENCED)
|
|
type="UNRELIABLE_SEQUENCED";
|
|
else if (reliability==RELIABLE_ORDERED)
|
|
type="RELIABLE_ORDERED";
|
|
|
|
if (receivedPacketNumber>packetNumber[streamNumber])
|
|
printf("Skipped %i got %i %s (channel %i).\n",packetNumber[streamNumber], receivedPacketNumber, type, streamNumber);
|
|
else if (receivedPacketNumber<packetNumber[streamNumber])
|
|
printf("Out of order packet! Expecting %i got %i %s (channel %i).\n",packetNumber[streamNumber], receivedPacketNumber, type, streamNumber);
|
|
else
|
|
printf("Got %i.%s.CH:%i.Len:%i.\n", packetNumber[streamNumber], type, streamNumber, packet->length);
|
|
|
|
// printf("Sent=%" PRINTF_64_BIT_MODIFIER "u Received=%" PRINTF_64_BIT_MODIFIER "u Diff=%i.\n", receivedTime, currentTime, (int)(currentTime - receivedTime));
|
|
|
|
packetNumber[streamNumber]=receivedPacketNumber+1;
|
|
break;
|
|
}
|
|
|
|
|
|
receiver->DeallocatePacket(packet);
|
|
packet = receiver->Receive();
|
|
}
|
|
}
|
|
|
|
// DO NOT COMMENT OUT THIS SLEEP!
|
|
// This sleep keeps RakNet responsive
|
|
#ifdef _WIN32
|
|
Sleep(0);
|
|
#else
|
|
usleep(0);
|
|
#endif
|
|
currentTime= SLNet::GetTimeMS();
|
|
}
|
|
|
|
if (sender)
|
|
SLNet::RakPeerInterface::DestroyInstance(sender);
|
|
if (receiver)
|
|
SLNet::RakPeerInterface::DestroyInstance(receiver);
|
|
|
|
if (fp)
|
|
fclose(fp);
|
|
|
|
return 1;
|
|
}
|