Files
SLikeNet/Samples/ReliableOrderedTest/ReliableOrderedTest.cpp
2025-11-24 14:19:51 +05:30

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;
}