int main(void)
{
	char ch;
	RakPeerInterface *rakPeer;

	// directoryDeltaTransfer is the main plugin that does the work for this sample.
	DirectoryDeltaTransfer directoryDeltaTransfer;
	// The fileListTransfer plugin is used by the DirectoryDeltaTransfer plugin and must also be registered (you could use this yourself too if you wanted, of course).
	FileListTransfer fileListTransfer;

	rakPeer = RakNetworkFactory::GetRakPeerInterface();
	rakPeer->AttachPlugin(&directoryDeltaTransfer);
	rakPeer->AttachPlugin(&fileListTransfer);
	// Get download progress notifications.  Handled by the plugin.
	rakPeer->SetSplitMessageProgressInterval(1);
	directoryDeltaTransfer.SetFileListTransferPlugin(&fileListTransfer);

	printf("This sample demonstrates the plugin to incrementally transfer compressed\n");
	printf("deltas of directories.  In essence, it's a simple autopatcher.\n");
	printf("Unlike the full autopatcher, it has no dependencies.  It is suitable for\n");
	printf("patching from non-dedicated servers at runtime.\n");
	printf("Difficulty: Intermediate\n\n");

	printf("Enter listen port. Enter for default. If running two instances on the\nsame computer, use 0 for the client.\n");
	unsigned short localPort;
	char str[256];
	gets(str);
	if (str[0]==0)
		localPort=60000;
	else
		localPort=atoi(str);
	SocketDescriptor socketDescriptor(localPort,0);
	if (rakPeer->Startup(8,30,&socketDescriptor, 1)==false)
	{
		RakNetworkFactory::DestroyRakPeerInterface(rakPeer);
		printf("RakNet initialize failed.  Possibly duplicate port.\n");
		return 1;
	}
	rakPeer->SetMaximumIncomingConnections(8);

	printf("Commands:\n");
	printf("(S)et application directory.\n");
	printf("(A)dd allowed uploads from subdirectory.\n");
	printf("(D)ownload from subdirectory.\n");
	printf("(C)lear allowed uploads.\n");
	printf("C(o)nnect to another system.\n");
	printf("(Q)uit.\n");

	RakNetTime nextStatTime = RakNet::GetTime() + 1000;

	Packet *p;
	while (1)
	{
		/*
		if (//directoryDeltaTransfer.GetNumberOfFilesForUpload()>0 &&
			RakNet::GetTime() > nextStatTime)
		{
			// If sending, periodically show connection stats
			char statData[2048];
			RakNetStatistics *statistics = rakPeer->GetStatistics(rakPeer->GetSystemAddressFromIndex(0));
		//	if (statistics->messagesOnResendQueue>0 || statistics->internalOutputQueueSize>0)
			if (rakPeer->GetSystemAddressFromIndex(0)!=UNASSIGNED_SYSTEM_ADDRESS)
			{
				StatisticsToString(statistics, statData, 2);
				printf("%s\n", statData);
			}
			
			nextStatTime=RakNet::GetTime()+5000;
		}
		*/

		// Process packets
		p=rakPeer->Receive();
		while (p)
		{
			if (p->data[0]==ID_NEW_INCOMING_CONNECTION)
				printf("ID_NEW_INCOMING_CONNECTION\n");
			else if (p->data[0]==ID_CONNECTION_REQUEST_ACCEPTED)
				printf("ID_CONNECTION_REQUEST_ACCEPTED\n");
			else if (p->data[0]==ID_DISCONNECTION_NOTIFICATION)
				printf("ID_DISCONNECTION_NOTIFICATION\n");
			else if (p->data[0]==ID_CONNECTION_LOST)
				printf("ID_CONNECTION_LOST\n");

			rakPeer->DeallocatePacket(p);
			p=rakPeer->Receive();
		}

		if (kbhit())
		{
			ch=getch();
			if (ch=='s')
			{
				printf("Enter application directory\n");
				gets(str);
				if (str[0]==0)
					strcpy(str, "C:/Temp");
				directoryDeltaTransfer.SetApplicationDirectory(str);
				printf("This directory will be prefixed to upload and download subdirectories.\n");
			}
			else if (ch=='a')
			{
				printf("Enter uploads subdirectory\n");
				gets(str);
				directoryDeltaTransfer.AddUploadsFromSubdirectory(str);
				printf("%i files for upload.\n", directoryDeltaTransfer.GetNumberOfFilesForUpload());
			}
			else if (ch=='d')
			{
				char subdir[256];
				char outputSubdir[256];
				printf("Enter remote subdirectory to download from.\n");
				printf("This directory may be any uploaded directory, or a subdir therein.\n");
				gets(subdir);
				printf("Enter subdirectory to output to.\n");
				gets(outputSubdir);
                
				unsigned short setId;
				setId=directoryDeltaTransfer.DownloadFromSubdirectory(subdir, outputSubdir, true, rakPeer->GetSystemAddressFromIndex(0), &transferCallback, HIGH_PRIORITY, 0, 0);
				if (setId==(unsigned short)-1)
					printf("Download failed.  Host unreachable.\n");
				else
					printf("Downloading set %i\n", setId);
			}
			else if (ch=='c')
			{
				directoryDeltaTransfer.ClearUploads();
				printf("Uploads cleared.\n");
			}
			else if (ch=='o')
			{
				char host[256];
				printf("Enter host IP: ");
				gets(host);
				if (host[0]==0)
					strcpy(host, "127.0.0.1");
				unsigned short remotePort;
				printf("Enter host port: ");
				gets(str);
				if (str[0]==0)
					remotePort=60000;
				else
					remotePort=atoi(str);
				rakPeer->Connect(host, remotePort, 0, 0);
				printf("Connecting.\n");
			}
			else if (ch=='q')
			{
				printf("Bye!\n");
				rakPeer->Shutdown(1000,0);
				break;
			}
		}

		// Keeps the threads responsive
		RakSleep(0);
	}

	RakNetworkFactory::DestroyRakPeerInterface(rakPeer);

	return 0;
}
int main(int argc, char **argv)
{
	printf("A simple client interface for the advanced autopatcher.\n");
	printf("Use DirectoryDeltaTransfer for a simpler version of an autopatcher.\n");
	printf("Difficulty: Intermediate\n\n");

	printf("Client starting...");
	SystemAddress serverAddress=UNASSIGNED_SYSTEM_ADDRESS;
	AutopatcherClient autopatcherClient;
	FileListTransfer fileListTransfer;
	autopatcherClient.SetFileListTransferPlugin(&fileListTransfer);
	unsigned short localPort=0;
	if (argc>=6)
	{
		localPort=atoi(argv[5]);
	}
#ifdef USE_TCP
	PacketizedTCP packetizedTCP;
	if (packetizedTCP.Start(localPort,1)==false)
	{
		printf("Failed to start TCP. Is the port already in use?");
		return 1;
	}
	packetizedTCP.AttachPlugin(&autopatcherClient);
	packetizedTCP.AttachPlugin(&fileListTransfer);
#else
	RakPeerInterface *rakPeer;
	rakPeer = RakNetworkFactory::GetRakPeerInterface();
	SocketDescriptor socketDescriptor(localPort,0);
	rakPeer->Startup(1,0,&socketDescriptor, 1);
	// Plugin will send us downloading progress notifications if a file is split to fit under the MTU 10 or more times
	rakPeer->SetSplitMessageProgressInterval(10);
	rakPeer->AttachPlugin(&autopatcherClient);
	rakPeer->AttachPlugin(&fileListTransfer);
#endif
	printf("started\n");
	char buff[512];
	if (argc<2)
	{
		printf("Enter server IP: ");
		gets(buff);
		if (buff[0]==0)
			//	strcpy(buff, "94.198.81.195");
			strcpy(buff, "127.0.0.1");
	}
	else
		strcpy(buff, argv[1]);

#ifdef USE_TCP
	packetizedTCP.Connect(buff,60000,false);
#else
	rakPeer->Connect(buff, 60000, 0, 0);
#endif

	printf("Connecting...\n");
	char appDir[512];
	if (argc<3)
	{
		printf("Enter application directory: ");
		gets(appDir);
		if (appDir[0]==0)
		{
			strcpy(appDir, "C:/temp2");
		}
	}
	else
		strcpy(appDir, argv[2]);
	char appName[512];
	if (argc<4)
	{
		printf("Enter application name: ");
		gets(appName);
		if (appName[0]==0)
			strcpy(appName, "TestApp");
	}
	else
		strcpy(appName, argv[3]);

	bool patchImmediately=argc>=5 && argv[4][0]=='1';

	if (patchImmediately==false)
		printf("Hit 'q' to quit, 'p' to patch, 'c' to cancel the patch. 'r' to reconnect. 'd' to disconnect.\n");
	else
		printf("Hit 'q' to quit, 'c' to cancel the patch.\n");

	char ch;
	Packet *p;
	while (1)
	{
#ifdef USE_TCP
		SystemAddress notificationAddress;
		notificationAddress=packetizedTCP.HasCompletedConnectionAttempt();
		if (notificationAddress!=UNASSIGNED_SYSTEM_ADDRESS)
		{
			printf("ID_CONNECTION_REQUEST_ACCEPTED\n");
			serverAddress=notificationAddress;
		}
		notificationAddress=packetizedTCP.HasNewIncomingConnection();
		if (notificationAddress!=UNASSIGNED_SYSTEM_ADDRESS)
			printf("ID_NEW_INCOMING_CONNECTION\n");
		notificationAddress=packetizedTCP.HasLostConnection();
		if (notificationAddress!=UNASSIGNED_SYSTEM_ADDRESS)
			printf("ID_CONNECTION_LOST\n");


		p=packetizedTCP.Receive();
		while (p)
		{
			if (p->data[0]==ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR)
			{
				char buff[256];
				RakNet::BitStream temp(p->data, p->length, false);
				temp.IgnoreBits(8);
				stringCompressor->DecodeString(buff, 256, &temp);
				printf("ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR\n");
				printf("%s\n", buff);
			}
			else if (p->data[0]==ID_AUTOPATCHER_FINISHED)
				printf("ID_AUTOPATCHER_FINISHED\n");
			else if (p->data[0]==ID_AUTOPATCHER_RESTART_APPLICATION)
				printf("Launch \"AutopatcherClientRestarter.exe autopatcherRestart.txt\"\nQuit this application immediately after to unlock files.\n");

			packetizedTCP.DeallocatePacket(p);
			p=packetizedTCP.Receive();
		}
#else
		p=rakPeer->Receive();
		while (p)
		{
			if (p->data[0]==ID_DISCONNECTION_NOTIFICATION)
				printf("ID_DISCONNECTION_NOTIFICATION\n");
			else if (p->data[0]==ID_CONNECTION_LOST)
				printf("ID_CONNECTION_LOST\n");
			else if (p->data[0]==ID_CONNECTION_REQUEST_ACCEPTED)
			{
				printf("ID_CONNECTION_REQUEST_ACCEPTED\n");
				serverAddress=p->systemAddress;
			}
			else if (p->data[0]==ID_CONNECTION_ATTEMPT_FAILED)
				printf("ID_CONNECTION_ATTEMPT_FAILED\n");
			else if (p->data[0]==ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR)
			{
				char buff[256];
				RakNet::BitStream temp(p->data, p->length, false);
				temp.IgnoreBits(8);
				stringCompressor->DecodeString(buff, 256, &temp);
				printf("ID_AUTOPATCHER_REPOSITORY_FATAL_ERROR\n");
				printf("%s\n", buff);
			}
			else if (p->data[0]==ID_AUTOPATCHER_FINISHED)
				printf("ID_AUTOPATCHER_FINISHED\n");
			else if (p->data[0]==ID_AUTOPATCHER_RESTART_APPLICATION)
				printf("Launch \"AutopatcherClientRestarter.exe autopatcherRestart.txt\"\nQuit this application immediately after to unlock files.\n");

			rakPeer->DeallocatePacket(p);
			p=rakPeer->Receive();
		}
#endif

		if (kbhit())
			ch=getch();
		else
			ch=0;

		if (ch=='q')
			break;
		else if (ch=='r')
		{
#ifdef USE_TCP
			packetizedTCP.Connect(buff,60000,false);
#else
			rakPeer->Connect(buff, 60000, 0, 0);
#endif
		}
		else if (ch=='d')
		{
#ifdef USE_TCP
			packetizedTCP.CloseConnection(serverAddress);
#else
			rakPeer->CloseConnection(serverAddress, true);
#endif
		}
		else if (ch=='p' || (serverAddress!=UNASSIGNED_SYSTEM_ADDRESS && patchImmediately==true))
		{
			patchImmediately=false;
			char lastUpdateDate[128];
			char restartFile[512];
			strcpy(restartFile, appDir);
			strcat(restartFile, "/autopatcherRestart.txt");
		//	printf("Enter last update date (only newer updates retrieved) or nothing to get all updates\n");
		//	gets(lastUpdateDate);
			lastUpdateDate[0]=0;

			if (autopatcherClient.PatchApplication(appName, appDir, lastUpdateDate, serverAddress, &transferCallback, restartFile, argv[0]))
			{
				printf("Patching process starting.\n");
			}
			else
			{
				printf("Failed to start patching.\n");
			}
		}
		else if (ch=='c')
		{
			autopatcherClient.Clear();
			printf("Autopatcher cleared.\n");
		}

		RakSleep(30);
	}

	// Dereference so the destructor doesn't crash
	autopatcherClient.SetFileListTransferPlugin(0);

#ifdef USE_TCP
	packetizedTCP.Stop();
#else
	rakPeer->Shutdown(500,0);
	RakNetworkFactory::DestroyRakPeerInterface(rakPeer);
#endif
	return 1;
}
/*
What is being done here is having 256 clients connect to one server, disconnect, connect again.

Do this for about 10 seconds. Then allow them all to connect for one last time.

This one has a nonblocking recieve so doesn't wait for connects or anything.
Just rapid connecting disconnecting.

Good ideas for changes:
After the last check run a eightpeers like test an add the conditions
of that test as well.

Make sure that if we initiate the connection we get a proper message
and if not we get a proper message. Add proper conditions.

Randomize sending the disconnect notes

Success conditions:
All connected normally.

Failure conditions:
Doesn't reconnect normally.

During the very first connect loop any connect returns false.

Connect function returns false and peer is not connected to anything.

*/
int ManyClientsOneServerNonBlockingTest::RunTest(DataStructures::List<RakString> params,bool isVerbose,bool noPauses)
{

	const int clientNum= 256;

	RakPeerInterface *clientList[clientNum];//A list of clients
	RakPeerInterface *server;//The server
	SystemAddress currentSystem;

	//SystemAddress currentSystem;

	Packet *packet;
	destroyList.Clear(false,_FILE_AND_LINE_);

	//Initializations of the arrays
	for (int i=0;i<clientNum;i++)
	{
		clientList[i]=RakPeerInterface::GetInstance();
		destroyList.Push(clientList[i],_FILE_AND_LINE_);

		clientList[i]->Startup(1,&SocketDescriptor(), 1);

	}

	server=RakPeerInterface::GetInstance();
	destroyList.Push(server,_FILE_AND_LINE_);
	server->Startup(clientNum, &SocketDescriptor(60000,0), 1);
	server->SetMaximumIncomingConnections(clientNum);

	//Connect all the clients to the server

	for (int i=0;i<clientNum;i++)
	{

		if (clientList[i]->Connect("127.0.0.1", 60000, 0,0)!=CONNECTION_ATTEMPT_STARTED)
		{

			if (isVerbose)
				DebugTools::ShowError("Problem while calling connect.\n",!noPauses && isVerbose,__LINE__,__FILE__);

			return 1;//This fails the test, don't bother going on.

		}

	}

	TimeMS entryTime=GetTimeMS();//Loop entry time

	DataStructures::List< SystemAddress  > systemList;
	DataStructures::List< RakNetGUID > guidList;

	if (isVerbose)
		printf("Entering disconnect loop \n");

	while(GetTimeMS()-entryTime<10000)//Run for 10 Secoonds
	{

		//Disconnect all clients IF connected to any from client side
		for (int i=0;i<clientNum;i++)
		{

			clientList[i]->GetSystemList(systemList,guidList);//Get connectionlist
			int len=systemList.Size();

			for (int j=0;j<len;j++)//Disconnect them all
			{

				clientList[i]->CloseConnection (systemList[j],true,0,LOW_PRIORITY); 	
			}

		}

		//RakSleep(100);

		//Connect

		for (int i=0;i<clientNum;i++)
		{

			currentSystem.SetBinaryAddress("127.0.0.1");
			currentSystem.port=60000;
			if(!CommonFunctions::ConnectionStateMatchesOptions (clientList[i],currentSystem,true,true,true,true) )//Are we connected or is there a pending operation ?
			{

				if (clientList[i]->Connect("127.0.0.1", 60000, 0,0)!=CONNECTION_ATTEMPT_STARTED)
				{

					if (isVerbose)
						DebugTools::ShowError("Problem while calling connect. \n",!noPauses && isVerbose,__LINE__,__FILE__);

					return 1;//This fails the test, don't bother going on.

				}
			}

		}

		//Server receive

		packet=server->Receive();

		if (isVerbose&&packet)
			printf("For server\n");

		while(packet)
		{

			switch (packet->data[0])
			{
			case ID_REMOTE_DISCONNECTION_NOTIFICATION:
				if (isVerbose)
					printf("Another client has disconnected.\n");

				break;
			case ID_REMOTE_CONNECTION_LOST:
				if (isVerbose)
					printf("Another client has lost the connection.\n");

				break;
			case ID_REMOTE_NEW_INCOMING_CONNECTION:
				if (isVerbose)              
					printf("Another client has connected.\n");
				break;
			case ID_CONNECTION_REQUEST_ACCEPTED:
				if (isVerbose)              
					printf("Our connection request has been accepted.\n");

				break;
			case ID_CONNECTION_ATTEMPT_FAILED:
				if (isVerbose)
					printf("A connection has failed.\n");

				break;

			case ID_NEW_INCOMING_CONNECTION:
				if (isVerbose)              
					printf("A connection is incoming.\n");

				break;
			case ID_NO_FREE_INCOMING_CONNECTIONS:
				if (isVerbose)              
					printf("The server is full.\n");

				break;

			case ID_ALREADY_CONNECTED:
				if (isVerbose)              
					printf("Already connected\n");

				break;

			case ID_DISCONNECTION_NOTIFICATION:
				if (isVerbose)
					printf("We have been disconnected.\n");
				break;
			case ID_CONNECTION_LOST:
				if (isVerbose)
					printf("Connection lost.\n");

				break;
			default:

				break;
			}

			server->DeallocatePacket(packet);

			// Stay in the loop as long as there are more packets.
			packet = server->Receive();
		}

		for (int i=0;i<clientNum;i++)//Receive for all peers
		{

			packet=clientList[i]->Receive();

			if (isVerbose&&packet)
				printf("For peer %i\n",i);

			while(packet)
			{

				switch (packet->data[0])
				{
				case ID_REMOTE_DISCONNECTION_NOTIFICATION:
					if (isVerbose)
						printf("Another client has disconnected.\n");

					break;
				case ID_REMOTE_CONNECTION_LOST:
					if (isVerbose)
						printf("Another client has lost the connection.\n");

					break;
				case ID_REMOTE_NEW_INCOMING_CONNECTION:
					if (isVerbose)              
						printf("Another client has connected.\n");
					break;
				case ID_CONNECTION_REQUEST_ACCEPTED:
					if (isVerbose)              
						printf("Our connection request has been accepted.\n");

					break;
				case ID_CONNECTION_ATTEMPT_FAILED:
					if (isVerbose)
						printf("A connection has failed.\n");

					break;

				case ID_NEW_INCOMING_CONNECTION:
					if (isVerbose)              
						printf("A connection is incoming.\n");

					break;
				case ID_NO_FREE_INCOMING_CONNECTIONS:
					if (isVerbose)              
						printf("The server is full.\n");

					break;

				case ID_ALREADY_CONNECTED:
					if (isVerbose)              
						printf("Already connected\n");

					break;

				case ID_DISCONNECTION_NOTIFICATION:
					if (isVerbose)
						printf("We have been disconnected.\n");
					break;
				case ID_CONNECTION_LOST:
					if (isVerbose)
						printf("Connection lost.\n");

					break;
				default:

					break;
				}

				clientList[i]->DeallocatePacket(packet);

				// Stay in the loop as long as there are more packets.
				packet = clientList[i]->Receive();
			}
		}
		RakSleep(0);//If needed for testing
	}

	entryTime=GetTimeMS();

	while(GetTimeMS()-entryTime<2000)//Run for 2 Secoonds to process incoming disconnects
	{

		//Server receive

		packet=server->Receive();

		if (isVerbose&&packet)
			printf("For server\n");

		while(packet)
		{

			switch (packet->data[0])
			{
			case ID_REMOTE_DISCONNECTION_NOTIFICATION:
				if (isVerbose)
					printf("Another client has disconnected.\n");

				break;
			case ID_REMOTE_CONNECTION_LOST:
				if (isVerbose)
					printf("Another client has lost the connection.\n");

				break;
			case ID_REMOTE_NEW_INCOMING_CONNECTION:
				if (isVerbose)              
					printf("Another client has connected.\n");
				break;
			case ID_CONNECTION_REQUEST_ACCEPTED:
				if (isVerbose)              
					printf("Our connection request has been accepted.\n");

				break;
			case ID_CONNECTION_ATTEMPT_FAILED:
				if (isVerbose)
					printf("A connection has failed.\n");

				break;

			case ID_NEW_INCOMING_CONNECTION:
				if (isVerbose)              
					printf("A connection is incoming.\n");

				break;
			case ID_NO_FREE_INCOMING_CONNECTIONS:
				if (isVerbose)              
					printf("The server is full.\n");

				break;

			case ID_ALREADY_CONNECTED:
				if (isVerbose)              
					printf("Already connected\n");

				break;

			case ID_DISCONNECTION_NOTIFICATION:
				if (isVerbose)
					printf("We have been disconnected.\n");
				break;
			case ID_CONNECTION_LOST:
				if (isVerbose)
					printf("Connection lost.\n");

				break;
			default:

				break;
			}

			server->DeallocatePacket(packet);

			// Stay in the loop as long as there are more packets.
			packet = server->Receive();
		}

		for (int i=0;i<clientNum;i++)//Receive for all peers
		{

			packet=clientList[i]->Receive();
			if (isVerbose&&packet)
				printf("For peer %i\n",i);

			while(packet)
			{

				switch (packet->data[0])
				{
				case ID_REMOTE_DISCONNECTION_NOTIFICATION:
					if (isVerbose)
						printf("Another client has disconnected.\n");

					break;
				case ID_REMOTE_CONNECTION_LOST:
					if (isVerbose)
						printf("Another client has lost the connection.\n");

					break;
				case ID_REMOTE_NEW_INCOMING_CONNECTION:
					if (isVerbose)              
						printf("Another client has connected.\n");
					break;
				case ID_CONNECTION_REQUEST_ACCEPTED:
					if (isVerbose)              
						printf("Our connection request has been accepted.\n");

					break;
				case ID_CONNECTION_ATTEMPT_FAILED:
					if (isVerbose)
						printf("A connection has failed.\n");

					break;

				case ID_NEW_INCOMING_CONNECTION:
					if (isVerbose)              
						printf("A connection is incoming.\n");

					break;
				case ID_NO_FREE_INCOMING_CONNECTIONS:
					if (isVerbose)              
						printf("The server is full.\n");

					break;

				case ID_ALREADY_CONNECTED:
					if (isVerbose)              
						printf("Already connected\n");

					break;

				case ID_DISCONNECTION_NOTIFICATION:
					if (isVerbose)
						printf("We have been disconnected.\n");
					break;
				case ID_CONNECTION_LOST:
					if (isVerbose)
						printf("Connection lost.\n");

					break;
				default:

					break;
				}

				clientList[i]->DeallocatePacket(packet);

				// Stay in the loop as long as there are more packets.
				packet = clientList[i]->Receive();
			}
		}
		RakSleep(0);//If needed for testing
	}

	//Connect

	for (int i=0;i<clientNum;i++)
	{

		currentSystem.SetBinaryAddress("127.0.0.1");
		currentSystem.port=60000;

		if(!CommonFunctions::ConnectionStateMatchesOptions (clientList[i],currentSystem,true,true,true,true) )//Are we connected or is there a pending operation ?
		{

			if (clientList[i]->Connect("127.0.0.1", 60000, 0,0)!=CONNECTION_ATTEMPT_STARTED)
			{

				clientList[i]->GetSystemList(systemList,guidList);//Get connectionlist
				int len=systemList.Size();

				if (isVerbose)
					DebugTools::ShowError("Problem while calling connect. \n",!noPauses && isVerbose,__LINE__,__FILE__);

				return 1;//This fails the test, don't bother going on.

			}
		}

	}

	entryTime=GetTimeMS();

	while(GetTimeMS()-entryTime<5000)//Run for 5 Secoonds
	{

		//Server receive

		packet=server->Receive();
		if (isVerbose&&packet)
			printf("For server\n");

		while(packet)
		{

			switch (packet->data[0])
			{
			case ID_REMOTE_DISCONNECTION_NOTIFICATION:
				if (isVerbose)
					printf("Another client has disconnected.\n");

				break;
			case ID_REMOTE_CONNECTION_LOST:
				if (isVerbose)
					printf("Another client has lost the connection.\n");

				break;
			case ID_REMOTE_NEW_INCOMING_CONNECTION:
				if (isVerbose)              
					printf("Another client has connected.\n");
				break;
			case ID_CONNECTION_REQUEST_ACCEPTED:
				if (isVerbose)              
					printf("Our connection request has been accepted.\n");

				break;
			case ID_CONNECTION_ATTEMPT_FAILED:
				if (isVerbose)
					printf("A connection has failed.\n");

				break;

			case ID_NEW_INCOMING_CONNECTION:
				if (isVerbose)              
					printf("A connection is incoming.\n");

				break;
			case ID_NO_FREE_INCOMING_CONNECTIONS:
				if (isVerbose)              
					printf("The server is full.\n");

				break;

			case ID_ALREADY_CONNECTED:
				if (isVerbose)              
					printf("Already connected\n");

				break;

			case ID_DISCONNECTION_NOTIFICATION:
				if (isVerbose)
					printf("We have been disconnected.\n");
				break;
			case ID_CONNECTION_LOST:
				if (isVerbose)
					printf("Connection lost.\n");

				break;
			default:

				break;
			}

			server->DeallocatePacket(packet);

			// Stay in the loop as long as there are more packets.
			packet = server->Receive();
		}

		for (int i=0;i<clientNum;i++)//Receive for all clients
		{

			packet=clientList[i]->Receive();
			if (isVerbose&&packet)
				printf("For peer %i\n",i);

			while(packet)
			{

				switch (packet->data[0])
				{
				case ID_REMOTE_DISCONNECTION_NOTIFICATION:
					if (isVerbose)
						printf("Another client has disconnected.\n");

					break;
				case ID_REMOTE_CONNECTION_LOST:
					if (isVerbose)
						printf("Another client has lost the connection.\n");

					break;
				case ID_REMOTE_NEW_INCOMING_CONNECTION:
					if (isVerbose)              
						printf("Another client has connected.\n");
					break;
				case ID_CONNECTION_REQUEST_ACCEPTED:
					if (isVerbose)              
						printf("Our connection request has been accepted.\n");

					break;
				case ID_CONNECTION_ATTEMPT_FAILED:
					if (isVerbose)
						printf("A connection has failed.\n");

					break;

				case ID_NEW_INCOMING_CONNECTION:
					if (isVerbose)              
						printf("A connection is incoming.\n");

					break;
				case ID_NO_FREE_INCOMING_CONNECTIONS:
					if (isVerbose)              
						printf("The server is full.\n");

					break;

				case ID_ALREADY_CONNECTED:
					if (isVerbose)              
						printf("Already connected\n");

					break;

				case ID_DISCONNECTION_NOTIFICATION:
					if (isVerbose)
						printf("We have been disconnected.\n");
					break;
				case ID_CONNECTION_LOST:
					if (isVerbose)
						printf("Connection lost.\n");

					break;
				default:

					break;
				}

				clientList[i]->DeallocatePacket(packet);

				// Stay in the loop as long as there are more packets.
				packet = clientList[i]->Receive();
			}
		}
		RakSleep(0);//If needed for testing
	}

	for (int i=0;i<clientNum;i++)
	{

		clientList[i]->GetSystemList(systemList,guidList);
		int connNum=guidList.Size();//Get the number of connections for the current peer
		if (connNum!=1)//Did we connect to all?
		{

			if (isVerbose)
				printf("Not all clients reconnected normally.\nFailed on clients number %i\n",i);

			if (isVerbose)
				DebugTools::ShowError("",!noPauses && isVerbose,__LINE__,__FILE__);

		
			

			return 2;

		}

	}

	

	if (isVerbose)
		printf("Pass\n");
	return 0;

}
Exemple #4
0
int main()
{
	Packet *packet;
	RakPeerInterface *rakPeer;
	bool isConnected=false;
	rakPeer=RakNetworkFactory::GetRakPeerInterface();
	char command[512];
	printf("This sample demonstrates connecting to the command console.\n");
	printf("using the RakNet transport protocol\n");
	printf("It's the equivalent of a secure telnet client\n");
	printf("See the 'CommandConsoleServer' project.\n");
	printf("Difficulty: Intermediate\n\n");

	printf("RakNet secure command console.\n");
	printf("Commands:\n");
	printf("/Connect\n");
	printf("/Disconnect\n");
	printf("/Quit\n");
	printf("Any other command goes to the remote console\n");
	while (1)
	{
		if (kbhit())
		{
			gets(command);

			if (stricmp(command, "/quit")==0)
			{
				printf("Goodbye.\n");
				rakPeer->Shutdown(500, 0);
				return 0;
			}
			else if (stricmp(command, "/disconnect")==0)
			{
				if (isConnected)
				{
					rakPeer->Shutdown(500, 0);
					isConnected=false;
					printf("Disconnecting.\n");
				}
				else
				{
					printf("Not currently connected.\n");
				}
			}
			else if (stricmp(command, "/connect")==0)
			{
				if (isConnected)
				{
					printf("Disconnect first.\n");
				}
				else
				{
					char ip[128];
					char remotePort[64];
					char password[512];
					char localPort[64];
					printf("Enter remote IP: ");
					do {
						gets(ip);
					} while(ip[0]==0);
					printf("Enter remote port: ");
					do {
						gets(remotePort);
					} while(remotePort[0]==0);
					printf("Enter local port (enter for 0): ");
					gets(localPort);
					if (localPort[0]==0)
					{
						strcpy(localPort, "0");
					}
					printf("Enter console password (enter for none): ");
					gets(password);
					SocketDescriptor socketDescriptor((int) atoi(localPort),0);
					if (rakPeer->Startup(1, 100, &socketDescriptor, 1))
					{
						int passwordLen;
						if (password[0])
							passwordLen=(int) strlen(password)+1;
						else
							passwordLen=0;
						if (rakPeer->Connect(ip, (int) atoi(remotePort), password, passwordLen))
							printf("Connecting...\nNote: if the password is wrong the other system will ignore us.\n");
						else
						{
							printf("Connect call failed.\n");
							rakPeer->Shutdown(0, 0);
						}
					}
					else
						printf("Initialize call failed.\n");					
					
				}				
			}
			else
			{
				if (isConnected)
				{
					RakNet::BitStream str;
					str.Write((unsigned char) ID_TRANSPORT_STRING);
					str.Write(command, (int) strlen(command)+1);
					rakPeer->Send(&str, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, true);
				}
				else
				{
					printf("You must be connected to send commands.\n");
				}
			}
		}

		packet = rakPeer->Receive();
		if (packet)
		{
			switch (packet->data[0])
			{
			case ID_DISCONNECTION_NOTIFICATION:
				printf("The server disconnected us.\n");
				isConnected=false;
				break;
			case ID_CONNECTION_BANNED:
				printf("We are banned from this server.\n");
				isConnected=false;
				break;
			case ID_CONNECTION_ATTEMPT_FAILED:
				printf("Connection attempt failed.\nThe password was wrong or there is no responsive machine at that IP/port.\n");
				isConnected=false;
				break;
			case ID_NO_FREE_INCOMING_CONNECTIONS:
				printf("Server is full.\n");
				isConnected=false;
				break;
			case ID_CONNECTION_LOST:
				printf("We lost the connection.\n");
				isConnected=false;
				break;
			case ID_CONNECTION_REQUEST_ACCEPTED:
				printf("Connection accepted.\n");
				isConnected=true;
				break;
			case ID_TRANSPORT_STRING:
				printf("%s", packet->data+1);
				break;
			}

			rakPeer->DeallocatePacket(packet);
		}

		// This sleep keeps RakNet responsive
#ifdef _WIN32
		Sleep(30);
#else
		usleep(30 * 1000);
#endif

	return 0;
	}
}
int main(int argc, char **argv)
{
	// Avoids the Error: Got a packet bigger than 'max_allowed_packet' bytes
	printf("Important: Requires that you first set the DB schema and the max packet size on the server.\n");
	printf("See DependentExtensions/AutopatcherMySQLRepository/readme.txt\n");
	
	RakPeerInterface *rakPeer;
	rakPeer = RakNetworkFactory::GetRakPeerInterface();
	printf("Server starting... ");
	SocketDescriptor socketDescriptor(60000,0);
	rakPeer->Startup(8,0,&socketDescriptor, 1);
	rakPeer->SetMaximumIncomingConnections(8);
	printf("started.\n");

	AutopatcherServer autopatcherServer;
	rakPeer->AttachPlugin(&autopatcherServer);
	AutopatcherMySQLRepository repository;
	autopatcherServer.SetAutopatcherRepositoryInterface(&repository);
	FLP_Printf progressIndicator;
	FileListTransfer fileListTransfer;
	fileListTransfer.SetCallback(&progressIndicator);
	autopatcherServer.SetFileListTransferPlugin(&fileListTransfer);
	rakPeer->AttachPlugin(&fileListTransfer);
	printf("Enter database password:\n");
	char password[128];
	char username[256];
	strcpy(username, "root");
	gets(password);
	if (password[0]==0)
		strcpy(password,"aaaa");
	char db[256];
	printf("Enter DB schema: ");
	gets(db);
	if (db[0]==0)
		strcpy(db,"autopatcher");
	if (!repository.Connect("localhost", username, password, db, 0, NULL, 0))
	{
		printf("Database connection failed.\n");
		return 1;
	}
	printf("Database connection suceeded.\n");
	printf("(D)rop database\n(C)reate database.\n(A)dd application\n(U)pdate revision.\n(R)emove application\n(Q)uit\n");

	char ch;
	Packet *p;
	while (1)
	{
		p=rakPeer->Receive();
		while (p)
		{
			if (p->data[0]==ID_NEW_INCOMING_CONNECTION)
				printf("ID_NEW_INCOMING_CONNECTION\n");
			else if (p->data[0]==ID_DISCONNECTION_NOTIFICATION)
				printf("ID_DISCONNECTION_NOTIFICATION\n");
			else if (p->data[0]==ID_CONNECTION_LOST)
				printf("ID_CONNECTION_LOST\n");

			rakPeer->DeallocatePacket(p);
			p=rakPeer->Receive();
		}

		if (kbhit())
		{
			ch=getch();
			if (ch=='q')
				break;
			else if (ch=='c')
			{
				if (repository.CreateAutopatcherTables()==false)
					printf("Error: %s\n", repository.GetLastError());
				else
					printf("Created\n");
			}
			else if (ch=='d')
			{
				if (repository.DestroyAutopatcherTables()==false)
					printf("Error: %s\n", repository.GetLastError());
				else
					printf("Destroyed\n");
			}
			else if (ch=='a')
			{
				printf("Enter application name to add: ");
				char appName[512];
				gets(appName);
				if (appName[0]==0)
					strcpy(appName, "TestApp");

				if (repository.AddApplication(appName, username)==false)
					printf("Error: %s\n", repository.GetLastError());
				else
					printf("Done\n");
			}
			else if (ch=='r')
			{
				printf("Enter application name to remove: ");
				char appName[512];
				gets(appName);
				if (appName[0]==0)
					strcpy(appName, "TestApp");

				if (repository.RemoveApplication(appName)==false)
					printf("Error: %s\n", repository.GetLastError());
				else
					printf("Done\n");
			}
			else if (ch=='u')
			{
				printf("Enter application name: ");
				char appName[512];
				gets(appName);
				if (appName[0]==0)
					strcpy(appName, "TestApp");

				printf("Enter application directory: ");
				char appDir[512];
				gets(appDir);
				if (appDir[0]==0)
					strcpy(appDir, "C:/temp");

				if (repository.UpdateApplicationFiles(appName, appDir, username, &progressIndicator)==false)
				{
					printf("Error: %s\n", repository.GetLastError());
				}
				else
				{
					printf("Update success.\n");
				}
			}
		}

		RakSleep(30);


	}

	RakNetworkFactory::DestroyRakPeerInterface(rakPeer);
}
int main(void)
{
	// Pointers to the interfaces of our server and client.
	// Note we can easily have both in the same program
	RakPeerInterface *client;
	RakPeerInterface *server;
	bool b;
	char str[256];
	char serverPort[30], clientPort[30];
	RakNetTime quitTime;
	// Holds packets
	Packet* p;	

	printf("A client / server sample showing how clients can broadcast offline packets\n");
	printf("to find active servers.\n");
	printf("Difficulty: Beginner\n\n");

	printf("Instructions:\nRun one or more servers on the same port.\nRun a client and it will get pongs from those servers.\n");
	printf("Run as (s)erver or (c)lient?\n");
	gets(str);

	if (str[0]=='s' || str[0]=='S')
	{
		client=0;
		server=RakNetworkFactory::GetRakPeerInterface();
		// A server
		printf("Enter the server port\n");
		gets(serverPort);
		if (serverPort[0]==0)
			strcpy(serverPort, "60001");

		printf("Starting server.\n");
		// The server has to be started to respond to pings.
		SocketDescriptor socketDescriptor(atoi(serverPort),0);
		b = server->Startup(2, 30, &socketDescriptor, 1);
		server->SetMaximumIncomingConnections(2);
		if (b)
			printf("Server started, waiting for connections.\n");
		else
		{ 
			printf("Server failed to start.  Terminating.\n");
			exit(1);
		}
	}
	else
	{
		client=RakNetworkFactory::GetRakPeerInterface();
		server=0;

		// Get our input
		printf("Enter the client port to listen on, or 0\n");
		gets(clientPort);
		if (clientPort[0]==0)
			strcpy(clientPort, "60000");
		printf("Enter the port to ping\n");
		gets(serverPort);
		if (serverPort[0]==0)
			strcpy(serverPort, "60001");
		SocketDescriptor socketDescriptor(atoi(clientPort),0);
		client->Startup(1, 30, &socketDescriptor, 1);

		// Connecting the client is very simple.  0 means we don't care about
		// a connectionValidationInteger, and false for low priority threads
		// All 255's mean broadcast
		client->Ping("255.255.255.255", atoi(serverPort), true);

		printf("Pinging\n");
	}

	printf("How many seconds to run this sample for?\n");
	gets(str);
	if (str[0]==0)
	{
		printf("Defaulting to 5 seconds\n");
		quitTime = RakNet::GetTime() + 5000;
	}
	else
		quitTime = RakNet::GetTime() + atoi(str) * 1000;

	// Loop for input
	while (RakNet::GetTime() < quitTime)
	{
		if (server)
			p = server->Receive();
		else 
			p = client->Receive();

		if (p==0)
		{
			SLEEP(30);
			continue;
		}
		if (server)
			server->DeallocatePacket(p);
		else
		{
			if (p->data[0]==ID_PONG)
			{
				RakNetTime time;
				memcpy((char*)&time, p->data+1, sizeof(RakNetTime));
				printf("Got pong from %s with time %i\n", p->systemAddress.ToString(), RakNet::GetTime() - time);
			}
			client->DeallocatePacket(p);
		}

		SLEEP(30);
	}

	// We're done with the network
	if (server)
		RakNetworkFactory::DestroyRakPeerInterface(server);
	if (client)
		RakNetworkFactory::DestroyRakPeerInterface(client);

	return 0;
}
void WorldLoop(CONNECT_INFO* cfg, Ref< UsersPool > OnlineUsers, Ref< CrossThreadQueue< string > > OutputQueue) {
	// Initialize the RakPeerInterface used throughout the entire server
	RakPeerInterface* rakServer = RakNetworkFactory::GetRakPeerInterface();

	// Initialize the PacketFileLogger plugin (for the logs)
	PacketFileLogger* msgFileHandler = NULL;
	if (cfg->logFile) {
		msgFileHandler = new PacketFileLogger();
		rakServer->AttachPlugin(msgFileHandler);
	}

	// Initialize security IF user has enabled it in config.ini
	InitSecurity(rakServer, cfg->useEncryption);

	// Initialize the SocketDescriptor
	SocketDescriptor socketDescriptor(cfg->listenPort, 0);

	// If the startup of the server is successful, print it to the console
	// Otherwise, quit the server (as the char server is REQUIRED for the
	// server to function properly)
	if (rakServer->Startup(8, 30, &socketDescriptor, 1)) {
		stringstream s;
		s << "world started! Listening on: " << cfg->listenPort << "\n";
		OutputQueue->Insert(s.str());
	} else exit(2);

	// Set max incoming connections to 8
	rakServer->SetMaximumIncomingConnections(8);

	// If msgFileHandler is not NULL, save logs of char server
	if (msgFileHandler != NULL) msgFileHandler->StartLog(".\\logs\\world");

	// Initialize the Packet class for the packets
	Packet* packet;

	// This will be used in the saving of packets below
	int i = 0;

	// This will be used in the saving of packets below...
	while (!LUNIterminate) {
		RakSleep(30);	// This sleep keeps RakNet responsive
		packet = rakServer->Receive(); // Recieve the packets from the server
		if (packet == NULL) continue; // If packet is NULL, just continue without processing anything

		// This will save all packets recieved from the client if running from DEBUG
		#ifdef DEBUG
			stringstream packetName;
			packetName << ".//Saves//World_Packet" << i << ".bin";

			SavePacket(packetName.str(), (char*)packet->data, packet->length);
			i++;
		#endif

		// Create and send packets back here according to the one we got
		switch (packet->data[0]) {
			case ID_USER_PACKET_ENUM:
				switch (packet->data[1]) {
					case GENERAL:
						if (packet->data[3] == 0) {	// thats just a formality so far since no other numbers occured for this case
							auto v = OpenPacket(".\\world\\init_aw.bin");
							ServerSendPacket(rakServer, v, packet->systemAddress);
						}
						break;

					case SERVER:

						switch (packet->data[3]) {
							case CLIENT_VALIDATION:
							{ 
								auto usr = OnlineUsers->Find(packet->systemAddress);
								//this packets contains ZoneId and something else... but what?
								// it starts whit: 53 05 00 02 00 00 00 00 -- -- (<-ZoneId) ?? ?? ??
								vector< uchar > v;
								if (usr != NULL && usr->nextcid == 2444680020) { //monkeybrown
									v = OpenPacket(".\\world\\monkeybrown\\char_aw2.bin");
								}
								else if (usr != NULL && usr->nextcid == 1534792735) { //gruntmonkey
									v = OpenPacket(".\\world\\gruntmonkey\\char_aw2.bin");
								}
								else if (usr != NULL && usr->nextcid == 1457240027) { //shafantastic
									v = OpenPacket(".\\world\\shastafantastic\\char_aw22.bin");
								}
								else { //cheekymonkey
									v = OpenPacket(".\\world\\char_aw2.bin");
								}

								#ifdef DEBUG
								if (v.size() > 0) {
									RakNet::BitStream bs( CleanPacket(v.data(), v.size()), v.size()-8, false );
									ZoneId zid;
									bs.Read(zid);
									stringstream s;
									s << "\nLoading world: " << zid << endl;
									OutputQueue->Insert(s.str());
								} else OutputQueue->Insert("\nWorld Error: can't load char_aw2.bin\n");
								#endif

								ServerSendPacket(rakServer, v, packet->systemAddress);
							}
								break;

							case CLIENT_LEVEL_LOAD_COMPLETE:
							{
								// Response: 05, 04
								// The answer to this is compressed data detailing character data
								// also since the answer seems to consist of a split packet, does RakNet automatically split the packets if the data is too big? or do we have to do something, if yes what?
								// byte 08 (2 or 4 bytes long? I guess 4...) seems to define the size of the data we send, no idea what the data itself is though...
								auto usr = OnlineUsers->Find(packet->systemAddress);

								// If the user is not equal to null and next character id = below number,
								// Open the packets of monkeybrown and load him into a world
								if (usr != NULL && usr->nextcid == 2444680020) {
									cout << "\n Replying to monkeybrown\n";
									auto v = OpenPacket(".\\world\\monkeybrown\\rocket_1a.bin");
									ServerSendPacket(rakServer, v, packet->systemAddress);

									v = OpenPacket(".\\world\\monkeybrown\\rocket_1b.bin");
									ServerSendPacket(rakServer, v, packet->systemAddress);

									v = OpenPacket(".\\world\\monkeybrown\\rocket_1c.bin");
									ServerSendPacket(rakServer, v, packet->systemAddress);

									v = OpenPacket(".\\world\\monkeybrown\\world_2a.bin");
									ServerSendPacket(rakServer, v, packet->systemAddress);
									// test, is this the right thing to do? there's no difference in the process when they are (not) sent so far
									v = OpenPacket(".\\world\\monkeybrown\\world_2b.bin");   // I assume these two are sent together?
									ServerSendPacket(rakServer, v, packet->systemAddress);

									for (int i = 0; i < 42; i++) {  // herpaderp
										stringstream fl;
										fl << ".\\world\\monkeybrown\\test\\world_2_" << (i + 1) << ".bin";
										auto v = OpenPacket(fl.str());
										ServerSendPacket(rakServer, v, packet->systemAddress);
									}

									v = OpenPacket(".\\world\\monkeybrown\\test\\world_2_1.bin");
									ServerSendPacket(rakServer, v, packet->systemAddress);

									for (int i = 42; i < 210; i++) {  // herpaderp
										stringstream fl;
										fl << ".\\world\\monkeybrown\\test\\world_2_" << (i + 1) << ".bin";
										auto v = OpenPacket(fl.str());
										ServerSendPacket(rakServer, v, packet->systemAddress);
									}
								} else { // Otherwise, reply to Cheekymonkey and open his packets
									cout << "\n Replying to cheekymonkey\n";
									auto v = OpenPacket(".\\world\\world_2a.bin");
									ServerSendPacket(rakServer, v, packet->systemAddress);
									// test, is this the right thing to do? there's no difference in the process when they are (not) sent so far
									v = OpenPacket(".\\world\\world_2b.bin");	// I assume these two are sent together?
									ServerSendPacket(rakServer, v, packet->systemAddress);
									for (int i = 0; i < 5; i++) {	// herpaderp
										stringstream fl;
										fl << ".\\world\\test\\world_2_" << (i + 1) << ".bin";
										auto v = OpenPacket(fl.str());
										ServerSendPacket(rakServer, v, packet->systemAddress);
									}
								}
							}
								break;

							case 22: //user moving / update request?
							{
								auto usr = OnlineUsers->Find(packet->systemAddress);
							#ifdef DEBUG
								OutputQueue->Insert("Received packet 22: " + RawDataToString(packet->data, packet->length) + "\n");
							#endif
							}
								break;

							case LUNI_WORLD_CHAT: //user wrote a chat message
							{
								if (packet->length >= 10 && RawDataToString(packet->data + packet->length - 10, 10, true) == "730064006f0077006e00") {//virus used to be here
								}

								// dummy try
								vector< uchar > v(packet->length);
								for (uint i = 0; i < packet->length; i++) v.push_back(packet->data[i]);
								ServerSendPacket(rakServer, v, packet->systemAddress);
							}
								break;

							case 5:
							{
							#ifdef DEBUG
								vector< uchar > t;
								for (int i = 8; i <= 11; i++) t.push_back(packet->data[i]);
								ulong cid = *(ulong*)t.data();
								//cout << "\nCharacter id is doing something?: " << cid;
							#endif
							}
								break;

							default:
								stringstream s;
								s << "\nworld received unknow pakcet: " << RawDataToString(packet->data, packet->length) << endl;
								OutputQueue->Insert(s.str());
						}

						break;

					default:
						stringstream s;
						s << "\nworld received unknow pakcet: " << RawDataToString(packet->data, packet->length) << endl;
						OutputQueue->Insert(s.str());
				}
				break;

			case ID_NEW_INCOMING_CONNECTION:
			#ifdef DEBUG
				OutputQueue->Insert("\n World is receiving a new connection...\n");
			#endif
				break;

			case ID_DISCONNECTION_NOTIFICATION:
			{
				auto usr = OnlineUsers->Find(packet->systemAddress);
				if (OnlineUsers->Remove(packet->systemAddress))
					OutputQueue->Insert("Disconnected " + usr->GetUsername() + "\n");
			}
				break;

			default:
				stringstream s;
				s << "\nworld received unknow pakcet: " << RawDataToString(packet->data, packet->length) << endl;
				OutputQueue->Insert(s.str());
		}

		rakServer->DeallocatePacket(packet);
	}

	stringstream s;
	s << "Quitting world\n";
	OutputQueue->Insert(s.str());

	rakServer->Shutdown(0);
	RakNetworkFactory::DestroyRakPeerInterface(rakServer);
}
int main(int argc, char *argv[])
{  
#ifndef WIN32
	setlinebuf(stdout);
#endif

	// Default values
	int listenPort = DEFAULTPORT;
	int connectionCount = 1000;

	time_t timerInterval = 10;	// 60 seconds
	time_t rotateCheckTimer = time(0) + timerInterval;
	int rotateSizeLimit = 50000000;	// 50 MB
	bool useLogFile = false;
	bool daemonMode = false;
	
	// Process command line arguments
	for (int i = 1; i < argc; i++)
	{
		if (strlen(argv[i]) == 2 && argc>=i+1)
		{
			switch (argv[i][1]) 
			{
				case 'd':
				{
					daemonMode = true;
					break;
				}
				case 'p':
				{
					listenPort = atoi(argv[i+1]);
					i++; // eat port number parameter
					if (listenPort < 1 || listenPort > 65535)
					{
						fprintf(stderr, "Master server port is invalid, should be between 0 and 65535.\nIt is also advisable to use a number above well known ports (>1024).\n");
						return 1;
					}
					break;
				}
				case 'c':
				{
					connectionCount = atoi(argv[i+1]);
					i++;
					if (connectionCount < 0)
					{
						fprintf(stderr, "Connection count must be higher than 0.\n");
						return 1;
					}
					break;
				}
				case 'l':
				{				
					useLogFile = Log::EnableFileLogging(logfile);
					break;
				}
				case 'e':
				{
					int debugLevel = atoi(argv[i+1]);
					Log::sDebugLevel = debugLevel;
					i++;
					if (debugLevel < 0 || debugLevel > 9)
					{
						fprintf(stderr, "Log level can be 0(errors), 1(warnings), 2(informational), 9(debug)\n");
						return 1;
					}
					break;
				}
				case 's':
				{
					int statDelay =  atoi(argv[i+1]);
					i++;
					if (statDelay < 0)
					{
						fprintf(stderr, "Statistics print delay must not be lower than 0. Use 0 to disable.\n");
						return 1;
					}
					databaseServer.SetStatDelay(statDelay);
					Log::printStats = true;
					break;
				}					
				case '?':
					usage();
					return 0;
				default:
					fprintf(stderr, "Parsing error, unknown parameter\n\n");
					usage();
					return 1;
			}
		}
		else
		{
			printf("Parsing error, incorrect parameters\n\n");
			usage();
			return 1;
		}
	}
	
#ifndef WIN32
	if (daemonMode)
	{
		printf("Running in daemon mode, file logging enabled...\n");
		if (!useLogFile)
			useLogFile = Log::EnableFileLogging(logfile);
		// Don't change cwd to /
		// Beware that log/pid files are placed wherever this was launched from
		daemon(1, 0);
	}
	
	if (!WriteProcessID(argv[0], &pidFile[0], fileBufSize))
		perror("Warning, failed to write own PID value to PID file\n");
#endif

	// Start the peers
	RakPeerInterface *masterPeer = RakNetworkFactory::GetRakPeerInterface();
	masterPeer->SetMaximumIncomingConnections(connectionCount);
	SocketDescriptor sd(listenPort,0);
	masterPeer->Startup(connectionCount, 30, &sd, 1);
	masterPeer->AttachPlugin(&databaseServer);
		
	Log::print_log("Unity master server version %s\n", VERSION);
	Log::print_log("Master server port set to %d\n",listenPort);
	Log::print_log("%d connection count limit\n", connectionCount);
	if (Log::printStats)
		Log::print_log("%d sec delay between statistics print to log\n", databaseServer.GetStatDelay());
	
	// Register signal handlers
#ifndef WIN32
	if (signal(SIGHUP, Log::RotateLogFile) == SIG_ERR)
		Log::error_log("Problem setting up hangup signal handler");
#endif
	if (signal(SIGINT, shutdown) == SIG_ERR || signal(SIGTERM, shutdown) == SIG_ERR)
		Log::error_log("Problem setting up terminate signal handler");
	else
		Log::print_log("To quit press Ctrl-C\n----------------------------------------------------\n");

	Packet *p;
	while (!quit)
	{
		p=masterPeer->Receive();
		while (p)
		{
			ProcessPacket(p);
			masterPeer->DeallocatePacket(p);
			p=masterPeer->Receive();
		}
		// Is it time to rotate the logs?
		if (useLogFile)
		{
			if (rotateCheckTimer < time(0))
			{
				// We should always be writing to the end of the stream, so the current position should give the total size
				int position = Log::GetLogSize();
				if (position > rotateSizeLimit) {
					Log::info_log("Rotating logs, size limit reached\n");
					Log::RotateLogFile(0);
				}
				rotateCheckTimer = time(0) + timerInterval;
			}
		}
		RakSleep(30);
	}

	if (pidFile)
	{
		if (remove(pidFile) != 0)
			fprintf(stderr, "Failed to remove PID file at %s\n", pidFile);
	}	
	masterPeer->Shutdown(100,0);
	RakNetworkFactory::DestroyRakPeerInterface(masterPeer);
				
	return 0;
}
int DroppedConnectionConvertTest::RunTest(DataStructures::List<RakString> params,bool isVerbose,bool noPauses)
{

	RakPeerInterface *server;
	RakPeerInterface *clients[NUMBER_OF_CLIENTS];
	unsigned index, connectionCount;
	SystemAddress serverID;
	Packet *p;
	unsigned short numberOfSystems;
	unsigned short numberOfSystems2;
	int sender;

	// Buffer for input (an ugly hack to keep *nix happy)
	//	char buff[256];

	// Used to refer to systems.  We already know the IP
	unsigned short serverPort = 20000;
	serverID.binaryAddress=inet_addr("127.0.0.1");
	serverID.port=serverPort;

	server=RakPeerInterface::GetInstance();
	destroyList.Clear(false,_FILE_AND_LINE_);
	destroyList.Push(server,_FILE_AND_LINE_);
	//	server->InitializeSecurity(0,0,0,0);
	SocketDescriptor socketDescriptor(serverPort,0);
	server->Startup(NUMBER_OF_CLIENTS, &socketDescriptor, 1);
	server->SetMaximumIncomingConnections(NUMBER_OF_CLIENTS);
	server->SetTimeoutTime(2000,UNASSIGNED_SYSTEM_ADDRESS);

	for (index=0; index < NUMBER_OF_CLIENTS; index++)
	{
		clients[index]=RakPeerInterface::GetInstance();
		destroyList.Push(clients[index],_FILE_AND_LINE_);
		SocketDescriptor socketDescriptor2(serverPort+1+index,0);
		clients[index]->Startup(1, &socketDescriptor2, 1);
		if (clients[index]->Connect("127.0.0.1", serverPort, 0, 0)!=CONNECTION_ATTEMPT_STARTED)
		{
			DebugTools::ShowError("Connect function failed.",!noPauses && isVerbose,__LINE__,__FILE__);
			return 2;

		}
		clients[index]->SetTimeoutTime(5000,UNASSIGNED_SYSTEM_ADDRESS);

		RakSleep(1000);
		if (isVerbose)
			printf("%i. ", index);
	}

	TimeMS entryTime=GetTimeMS();//Loop entry time

	int seed = 12345;
	if (isVerbose)
		printf("Using seed %i\n", seed);
	seedMT(seed);//specify seed to keep execution path the same.

	int randomTest;

	bool dropTest=false;
	RakTimer timeoutWaitTimer(1000);

	while (GetTimeMS()-entryTime<30000)//run for 30 seconds.
	{
		// User input

		randomTest=randomMT() %4;

		if(dropTest)
		{

			server->GetConnectionList(0, &numberOfSystems);
			numberOfSystems2=numberOfSystems;

			connectionCount=0;
			for (index=0; index < NUMBER_OF_CLIENTS; index++)
			{
				clients[index]->GetConnectionList(0, &numberOfSystems);
				if (numberOfSystems>1)
				{
					if (isVerbose)
					{
						printf("Client %i has %i connections\n", index, numberOfSystems);
						DebugTools::ShowError("Client has more than one connection",!noPauses && isVerbose,__LINE__,__FILE__);
						return 1;
					}

				}
				if (numberOfSystems==1)
				{
					connectionCount++;
				}
			}

			if (connectionCount!=numberOfSystems2)
			{
				if (isVerbose)
					DebugTools::ShowError("Timeout on dropped clients not detected",!noPauses && isVerbose,__LINE__,__FILE__);
				return 3;
			}

		}
		dropTest=false;

		switch(randomTest)
		{

		case 0:
			{
				index = randomMT() % NUMBER_OF_CLIENTS;

				clients[index]->GetConnectionList(0, &numberOfSystems);
				clients[index]->CloseConnection(serverID, false,0);
				if (numberOfSystems==0)
				{
					if (isVerbose)
						printf("Client %i silently closing inactive connection.\n",index);
				}
				else
				{
					if (isVerbose)
						printf("Client %i silently closing active connection.\n",index);
				}
			}

			break;
		case 1:
			{
				index = randomMT() % NUMBER_OF_CLIENTS;

				clients[index]->GetConnectionList(0, &numberOfSystems);

				if(!CommonFunctions::ConnectionStateMatchesOptions (clients[index],serverID,true,true,true,true) )//Are we connected or is there a pending operation ?
				{
					if (clients[index]->Connect("127.0.0.1", serverPort, 0, 0)!=CONNECTION_ATTEMPT_STARTED)
					{

						DebugTools::ShowError("Connect function failed.",!noPauses && isVerbose,__LINE__,__FILE__);
						return 2;

					}
				}
				if (numberOfSystems==0)
				{
					if (isVerbose)
						printf("Client %i connecting to same existing connection.\n",index);

				}
				else
				{
					if (isVerbose)
						printf("Client %i connecting to closed connection.\n",index);
				}
			}

			break;
		case 2:
			{

				if (isVerbose)
					printf("Randomly connecting and disconnecting each client\n");
				for (index=0; index < NUMBER_OF_CLIENTS; index++)
				{
					if (NUMBER_OF_CLIENTS==1 || (randomMT()%2)==0)
					{
						if (clients[index]->IsActive())
						{

							int randomTest2=randomMT() %2;
							if (randomTest2)
								clients[index]->CloseConnection(serverID, false, 0);
							else
								clients[index]->CloseConnection(serverID, true, 0);
						}
					}
					else
					{
						if(!CommonFunctions::ConnectionStateMatchesOptions (clients[index],serverID,true,true,true,true) )//Are we connected or is there a pending operation ?
						{
							if (clients[index]->Connect("127.0.0.1", serverPort, 0, 0)!=CONNECTION_ATTEMPT_STARTED)
							{
								DebugTools::ShowError("Connect function failed.",!noPauses && isVerbose,__LINE__,__FILE__);
								return 2;

							}
						}
					}
				}
			}
			break;

		case 3:
			{

				if (isVerbose)
					printf("Testing if clients dropped after timeout.\n");
				timeoutWaitTimer.Start();
						//Wait half the timeout time, the other half after receive so we don't drop all connections only missing ones, Active ait so the threads run on linux
				while (!timeoutWaitTimer.IsExpired())
				{
				RakSleep(50);
				}
				dropTest=true;

			}
			break;
		default:
			// Ignore anything else
			break;
		}

		server->GetConnectionList(0, &numberOfSystems);
		numberOfSystems2=numberOfSystems;
		if (isVerbose)
			printf("The server thinks %i clients are connected.\n", numberOfSystems);
		connectionCount=0;
		for (index=0; index < NUMBER_OF_CLIENTS; index++)
		{
			clients[index]->GetConnectionList(0, &numberOfSystems);
			if (numberOfSystems>1)
			{
				if (isVerbose)
				{
					printf("Client %i has %i connections\n", index, numberOfSystems);
					DebugTools::ShowError("Client has more than one connection",!noPauses && isVerbose,__LINE__,__FILE__);
					return 1;
				}

			}
			if (numberOfSystems==1)
			{
				connectionCount++;
			}
		}

		if (isVerbose)
			printf("%i clients are actually connected.\n", connectionCount);
		if (isVerbose)
			printf("server->NumberOfConnections==%i.\n", server->NumberOfConnections());

		//}

		// Parse messages

		while (1)
		{
			p = server->Receive();
			sender=NUMBER_OF_CLIENTS;
			if (p==0)
			{
				for (index=0; index < NUMBER_OF_CLIENTS; index++)
				{
					p = clients[index]->Receive();
					if (p!=0)
					{
						sender=index;
						break;						
					}
				}
			}

			if (p)
			{
				switch (p->data[0])
				{
				case ID_CONNECTION_REQUEST_ACCEPTED:
					if (isVerbose)
						printf("%i: %ID_CONNECTION_REQUEST_ACCEPTED from %i.\n",sender, p->systemAddress.port);
					break;
				case ID_DISCONNECTION_NOTIFICATION:
					// Connection lost normally
					if (isVerbose)
						printf("%i: ID_DISCONNECTION_NOTIFICATION from %i.\n",sender, p->systemAddress.port);
					break;

				case ID_NEW_INCOMING_CONNECTION:
					// Somebody connected.  We have their IP now
					if (isVerbose)
						printf("%i: ID_NEW_INCOMING_CONNECTION from %i.\n",sender, p->systemAddress.port);
					break;


				case ID_CONNECTION_LOST:
					// Couldn't deliver a reliable packet - i.e. the other system was abnormally
					// terminated
					if (isVerbose)
						printf("%i: ID_CONNECTION_LOST from %i.\n",sender, p->systemAddress.port);
					break;

				case ID_NO_FREE_INCOMING_CONNECTIONS:
					if (isVerbose)
						printf("%i: ID_NO_FREE_INCOMING_CONNECTIONS from %i.\n",sender, p->systemAddress.port);
					break;

				default:
					// Ignore anything else
					break;
				}
			}
			else
				break;

			if (sender==NUMBER_OF_CLIENTS)
				server->DeallocatePacket(p);
			else
				clients[sender]->DeallocatePacket(p);
		}
		if (dropTest)
		{
			//Trigger the timeout if no recieve
			timeoutWaitTimer.Start();
			while (!timeoutWaitTimer.IsExpired())
			{
			RakSleep(50);
			}
		}
		// 11/29/05 - No longer necessary since I added the keepalive
		/*
		// Have everyone send a reliable packet so dropped connections are noticed.
		ch=255;
		server->Send((char*)&ch, 1, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true);

		for (index=0; index < NUMBER_OF_CLIENTS; index++)
		clients[index]->Send((char*)&ch, 1, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true);
		*/

		// Sleep so this loop doesn't take up all the CPU time

		RakSleep(10);

	}

	return 0;
}
int main(void)
{
	printf("DEPRECIATED - Use LightweightDatabase instead\n");

	BitStream bitStream;
	char str[256];
	char ch;
	MasterClient masterClient;
	RakPeerInterface *testGameServerOrClient;
	unsigned int serverListSize, index;
	bool identiferFound;
	const char *outputString;
	int outputInt;
	Packet *p;

	// Create a fake game
	testGameServerOrClient = RakNetworkFactory::GetRakPeerInterface();
	testGameServerOrClient->Initialize(8, 60003, 0);
	testGameServerOrClient->SetMaximumIncomingConnections(8);
	testGameServerOrClient->AttachPlugin(&masterClient);

	printf("This project shows how to use the master client.\n");
	printf("The master client is used by game servers to advertise themselves.\n");
	printf("On the master server and by game clients to download a list of game servers\n");
	printf("Difficulty: Intermediate\n\n");

	if (masterClient.Connect("127.0.0.1", 60000))
		printf("Master client connecting...\n");
	else
		printf("Master client failed to start or connect.\n");

	printf("(Q)uit\n(q)uery master server\n(l)ist server\n(d)elist server\n(D)isconnect from the master server.\n(a)dd rule\n(r)emove rule\n(p)ing server list\n(C)onnect to the master server.\n(c)onnect to another game, using NAT punch-through with master server, bypassing most NATs\n(SPACE) print server list\n");
	char buff[256];
	while (1)
	{
		if (kbhit())
		{
			READCHAR(buff);
			if (ch=='Q')
				break;
			if (ch=='q')
			{
				masterClient.ClearQueryRules();
				printf("Enter query key 1/2 or enter for none: ");
				gets(str);
				masterClient.AddQueryRule(str);
				printf("Enter query key 2/2 or enter for none: ");
				gets(str);
				masterClient.AddQueryRule(str);
				masterClient.QueryMasterServer();
				printf("Server queried.  Press space to see server list.\n");
			}
			else if (ch=='l')
			{
				printf("Uploading game server.  Query to see it.\n");
				masterClient.ListServer();
			}
			else if (ch=='d')
			{
				printf("Server delisted.  Query to update our own list.\n");
				masterClient.DelistServer();
			}
			else if (ch=='D')
			{
				printf("Disconnected.\n");
				PlayerID playerId;
				testGameServerOrClient->IPToPlayerID("127.0.0.1", 60000, &playerId);
				testGameServerOrClient->CloseConnection(playerId, true, 0);
			}
			else if (ch=='C')
			{
				if (masterClient.Connect("127.0.0.1", 60000))
					printf("Master client connecting...\n");
				else
					printf("Master client failed to start or connect.\n");
			}
			else if (ch=='a')
			{
				printf("Adding sample rules.  Query to update our own list.\n");
				masterClient.PostRule("Game name", "My big game o' death.", 0);
				masterClient.PostRule("Game type", "Death match", 0);
				masterClient.PostRule("Score",0, 100);
			}
			else if (ch=='r')
			{
				printf("Removing rules. Query to update our own list.\n");
				masterClient.RemoveRule("Game type");
				masterClient.RemoveRule("Game name");
				masterClient.RemoveRule("Score");
			}
			else if (ch=='p')
			{
				printf("Pinging any servers in our list\n");
				masterClient.PingServers();
			}
			else if (ch=='c')
			{
				char ip[22];
				printf("Sending connection attempt notification to master server\n");
				printf("Enter IP of server from game list: ");
				gets(ip);
				printf("Enter port: ");
				gets(str);
				if (ip[0]!=0 && str[0]!=0)
				{
					masterClient.ConnectionAttemptNotification(ip, atoi(str));
					printf("Sent connection attempt notification to the server the master server\n");
				}
				else
				{
					printf("Aborting...");
				}				
			}
			else if (ch==' ')
			{
				serverListSize=masterClient.GetServerListSize();
				if (serverListSize==0)
				{
					printf("No servers in list\n");
				}
				else
				{
					for (index=0; index < serverListSize; index++)
					{
						printf("%i. ", index);
						outputString=masterClient.GetServerListRuleAsString(index, "IP", &identiferFound);
						if (identiferFound)
							printf("%s:", outputString);
						else
							printf("NO_IP:");
						outputInt=masterClient.GetServerListRuleAsInt(index, "Port", &identiferFound);
						if (identiferFound)
							printf("%i ", outputInt);
						else
							printf("NO_PORT ");
						outputInt=masterClient.GetServerListRuleAsInt(index, "Ping", &identiferFound);
						if (identiferFound)
							printf("%i ", outputInt);
						else
							printf("NO_PING ");
						outputString=masterClient.GetServerListRuleAsString(index, "Game type", &identiferFound);
						if (identiferFound)
							printf("%s ", outputString);
						else
							printf("NO_GT ");
						outputString=masterClient.GetServerListRuleAsString(index, "Game name", &identiferFound);
						if (identiferFound)
							printf("%s ", outputString);
						else
							printf("NO_GN ");
						outputInt=masterClient.GetServerListRuleAsInt(index, "Score", &identiferFound);
						if (identiferFound)
							printf("%i\n", outputInt);
						else
							printf("NO_SCORE\n");
					}
				}
			}
			ch=0;
		}

		p = testGameServerOrClient->Receive();
		while (p)
		{
			// Ignore any game packets.  The master server plugin handles everything.
			testGameServerOrClient->DeallocatePacket(p);
			// Call Receive every update to keep the plugin going
			p = testGameServerOrClient->Receive();
		}

#ifdef _WIN32
		Sleep(30);
#else
		usleep(30 * 1000);
#endif
	}

	masterClient.Disconnect();
	RakNetworkFactory::DestroyRakPeerInterface(testGameServerOrClient);

	return 0;
}
//This static method is called when the user wants to host a server
void Session::StartHost(void* pVoid){
	//A parameter list is given with needed variables
	ArgumentList* pArgumentList = (ArgumentList*)pVoid;
	RakPeerInterface *pServer;
	//Filling my fields from argument list.
	pServer=pArgumentList->inter;
	std::string password = pArgumentList->password;
	int port = pArgumentList->port;
	RakNet::RPC3* rpc3Inst = pArgumentList->rpc3;
	//map that keeps track of who is who
	std::map<RakNet::SystemAddress, std::string> clientCharacterMap;

	//Register the functions we want to call RPC3 upon
	RPC3_REGISTER_FUNCTION(rpc3Inst, ReceiveInformation);
	RPC3_REGISTER_FUNCTION(rpc3Inst, UpdateCharacter);
	RPC3_REGISTER_FUNCTION(rpc3Inst, UpdateCharacterVelocity);
	RPC3_REGISTER_FUNCTION(rpc3Inst, SyncClients);
	RPC3_REGISTER_FUNCTION(rpc3Inst, ReceiveID);
	RPC3_REGISTER_FUNCTION(rpc3Inst, RemoveCharacter);
	RPC3_REGISTER_FUNCTION(rpc3Inst, AddScore);
	
	//Set up the host using RakNet
	pServer->SetIncomingPassword(password.c_str(), (int)strlen(password.c_str()));
	pServer->SetTimeoutTime(5000,UNASSIGNED_SYSTEM_ADDRESS);
	SystemAddress clientID=UNASSIGNED_SYSTEM_ADDRESS;
	RakNet::SocketDescriptor socketDescriptor(port,0);
	socketDescriptor.socketFamily=AF_INET;
	bool b = pServer->Startup(10,&socketDescriptor, 1 );
	pServer->SetMaximumIncomingConnections(10);

	pServer->SetOccasionalPing(true);
	pServer->SetUnreliableTimeout(1000);

	DataStructures::List<RakNetSmartPtr<RakNetSocket> > sockets;
	pServer->GetSockets(sockets);	
	
	// Holds packets
	Packet* p;
	// Record the first client that connects to us so we can pass it to the ping function
	clientID=UNASSIGNED_SYSTEM_ADDRESS;

	pServer->AttachPlugin(rpc3Inst);

	char message[2048];

	// Loop for input
	while (threading)
	{
		for (p=pServer->Receive(); p; pServer->DeallocatePacket(p), p=pServer->Receive())
		{
			switch (p->data[0])
			{
			case ID_DISCONNECTION_NOTIFICATION:
				{
				printf("ID_DISCONNECTION_NOTIFICATION\n");
				RakString name(clientCharacterMap[p->systemAddress].c_str());
				RemoveCharacter(name);
				rpc3Inst->CallC("RemoveCharacter", name);
				break;
				}
			case ID_ALREADY_CONNECTED:
				printf("ID_ALREADY_CONNECTED\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_UNCONNECTED_PONG:
				// Found the server
				pServer->Connect(p->systemAddress.ToString(false),p->systemAddress.GetPort(),0,0,0);
				break;
			case ID_CONNECTION_REQUEST_ACCEPTED:
				// This tells the client they have connected
				printf("ID_CONNECTION_REQUEST_ACCEPTED\n");
				//Session::SendInformation(RakNet::RakString("The italians are invading utrecht!"), rpc3Inst, 0);
				//Game::getSingletonPtr()->
				break;
			case ID_NEW_INCOMING_CONNECTION:
			{
				//When there is a new incoming connection we are change the local player to the host
				printf("New incoming connection\n");
				Game::getSingletonPtr()->getLocalPlayer()->SetNetworkName("PlayerHost");
				std::stringstream ss, ss2;
				ss << "Client" << (Game::getSingletonPtr()->GetCharacters().size()+1);
				//create a new character for the client
				Game::getSingletonPtr()->CreateCharacter(ss.str());
				clientCharacterMap[p->systemAddress] = ss.str();

				RPC3::CallExplicitParameters params;
				params.systemAddress = p->systemAddress;
				params.broadcast = false;
				//Make sure the client knows who he is
				rpc3Inst->CallExplicit("ReceiveID", &params, RakString::RakString(ss.str().c_str()));
				ss2 << Game::getSingletonPtr()->GetCharacters().size();
				//Synchronize the players with all clients; make sure they have all the characters on the screen
				RPC3::CallExplicitParameters params2;
				//params2.systemAddress = p->systemAddress;
				params2.broadcast = true;
				rpc3Inst->CallExplicit("SyncClients", &params2, RakNet::RakString(ss2.str().c_str()));
				//rpc3Inst->CallC("SyncClients", RakNet::RakString(ss2.str().c_str()));
				break;
			}				
			case ID_RPC_REMOTE_ERROR:
				{
					// Recipient system returned an error
					switch (p->data[1])
					{
					case RakNet::RPC_ERROR_NETWORK_ID_MANAGER_UNAVAILABLE:
						printf("RPC_ERROR_NETWORK_ID_MANAGER_UNAVAILABLE\n");
						break;
					case RakNet::RPC_ERROR_OBJECT_DOES_NOT_EXIST:
						printf("RPC_ERROR_OBJECT_DOES_NOT_EXIST\n");
						break;
					case RakNet::RPC_ERROR_FUNCTION_INDEX_OUT_OF_RANGE:
						printf("RPC_ERROR_FUNCTION_INDEX_OUT_OF_RANGE\n");
						break;
					case RakNet::RPC_ERROR_FUNCTION_NOT_REGISTERED:
						printf("RPC_ERROR_FUNCTION_NOT_REGISTERED\n");
						break;
					case RakNet::RPC_ERROR_FUNCTION_NO_LONGER_REGISTERED:
						printf("RPC_ERROR_FUNCTION_NO_LONGER_REGISTERED\n");
						break;
					case RakNet::RPC_ERROR_CALLING_CPP_AS_C:
						printf("RPC_ERROR_CALLING_CPP_AS_C\n");
						break;
					case RakNet::RPC_ERROR_CALLING_C_AS_CPP:
						printf("RPC_ERROR_CALLING_C_AS_CPP\n");
						break;
					}
					printf("Function: %s", p->data+2);
				}
			}
		}
	}
	pServer->Shutdown(30,0);
	RakNet::RakPeerInterface::DestroyInstance(pServer);
	delete rpc3Inst;
}
int main(void)
{
	MasterServer masterServer;
	int serverListSize;
	const char *outputString;
	int outputInt;
	bool identiferFound;
	int index;
	char ch;
	Packet *p;

	RakPeerInterface *testGameMasterServer;

	testGameMasterServer = RakNetworkFactory::GetRakPeerInterface();
	testGameMasterServer->Initialize(10, 60000, 0);
	testGameMasterServer->SetMaximumIncomingConnections(8);
	testGameMasterServer->AttachPlugin(&masterServer);

	printf("This project shows how to use the master server.\n");
	printf("The master server is a plugin that maintains a list of games uplodated.\n");
	printf("by the master client.\n");
	printf("Difficulty: Beginner\n\n");

	printf("(p)rint\n(q)uit\n");
	char buff[256];

	while (1)
	{
		if (kbhit())
		{
			READCHAR(buff);
			if (ch=='q')
				break;
			else if (ch=='p')
			{
				serverListSize=masterServer.GetServerListSize();
				if (serverListSize==0)
				{
					printf("No servers in list\n");
				}
				else
				{
					for (index=0; index < serverListSize; index++)
					{
						printf("%i. ", index);
						outputString=masterServer.GetServerListRuleAsString(index, "IP", &identiferFound);
						if (identiferFound)
							printf("%s:", outputString);
						else
							printf("NO_IP:");
						outputInt=masterServer.GetServerListRuleAsInt(index, "Port", &identiferFound);
						if (identiferFound)
							printf("%i ", outputInt);
						else
							printf("NO_PORT ");
						outputString=masterServer.GetServerListRuleAsString(index, "Game type", &identiferFound);
						if (identiferFound)
							printf("%s ", outputString);
						else
							printf("NIL_GT ");
						outputString=masterServer.GetServerListRuleAsString(index, "Game name", &identiferFound);
						if (identiferFound)
							printf("%s ", outputString);
						else
							printf("NIL_GN ");
						outputInt=masterServer.GetServerListRuleAsInt(index, "Score", &identiferFound);
						if (identiferFound)
							printf("%i\n", outputInt);
						else
							printf("NO_SCORE\n");
					}
				}
			}
			ch=0;
		}

		p = testGameMasterServer->Receive();
		while (p)
		{
			// Ignore any game packets.  The master server plugin handles everything.
			testGameMasterServer->DeallocatePacket(p);
			// Call Receive every update to keep the plugin going
			p = testGameMasterServer->Receive();
		}
		

#ifdef _WIN32
		Sleep(30);
#else
		usleep(30 * 1000);
#endif
	}

	return 0;
}
void AuthLoop(CONNECT_INFO* cfg, Ref< UsersPool > OnlineUsers, Ref< CrossThreadQueue< string > > OutputQueue) {
	RakPeerInterface* rakServer = RakNetworkFactory::GetRakPeerInterface();

	PacketFileLogger* msgFileHandler = NULL;
	if (cfg->logFile) {
		msgFileHandler = new PacketFileLogger();
		rakServer->AttachPlugin(msgFileHandler);
	}

	InitSecurity(rakServer, cfg->useEncryption);
	SocketDescriptor socketDescriptor(cfg->listenPort, 0);

	if (rakServer->Startup(8, 30, &socketDescriptor, 1)) {
		stringstream s;
		s << "auth started! Listening on: " << cfg->listenPort << "\n";
		OutputQueue->Insert(s.str());
	} else QuitError("auth server init error!");
	rakServer->SetMaximumIncomingConnections(8);

	if (msgFileHandler != NULL) msgFileHandler->StartLog(".\\logs\\auth");

	Packet* packet;

	while (!LUNIterminate) {
		RakSleep(30);	// This sleep keeps RakNet responsive
		packet = rakServer->Receive();
		if (packet == NULL) continue;
		PrintPacketInfo(packet, msgFileHandler);

		switch (packet->data[0]) {
			case ID_LEGO_PACKET:

				switch (packet->data[1]) {
					case LUNI_INITAW:
						if (packet->data[3] == 0) {	// thats just a formality so far since no other numbers occured for this case
							// response: 00, 00
							auto v = OpenPacket(".\\auth\\init_aw.bin");
							// bytes 8-10 is the game version (same numbers are mentioned in the game log)
							// the client expects it to be the same that he sent (otherwise he displays "server is being updated" and disconnects)
							ServerSendPacket(rakServer, v, packet->systemAddress);
						}
						break;

					case LUNI_LOGIN: //user logging into server
						{
							auto usr = HandleUserLogin(rakServer, packet, cfg, OnlineUsers);
							if( usr != NULL ) OutputQueue->Insert("\n" + usr->GetUsername() + " Logged-in\n");
						#ifdef DEBUG
							else OutputQueue->Insert("\n Login failed!\n");
						#endif
						}
						break;

					default:
						stringstream s;
						s << "\nauth received unknow pakcet: " << RawDataToString(packet->data, packet->length) << endl;
						OutputQueue->Insert(s.str());
				}

				break;

			case ID_NEW_INCOMING_CONNECTION:
#			ifdef DEBUG
				OutputQueue->Insert("\n Auth is receiving a new connection...\n");
			#endif
				break;

			case ID_DISCONNECTION_NOTIFICATION: // do nothing
				break;

			default:
				stringstream s;
				s << "\nauth received unknow pakcet: " << RawDataToString(packet->data, packet->length) << endl;
				OutputQueue->Insert(s.str());
		}

		rakServer->DeallocatePacket(packet);
	}

	stringstream s;
	s << "Quitting auth\n";
	OutputQueue->Insert(s.str());

	rakServer->Shutdown(0);
	RakNetworkFactory::DestroyRakPeerInterface(rakServer);
}
int main(void)
{
	RakPeerInterface *server;
	RakPeerInterface *clients[NUMBER_OF_CLIENTS];
	unsigned index, connectionCount, unacknowledgedPacketSize;
	unsigned char ch;
	PlayerID serverID;
	Packet *p;
	unsigned short numberOfSystems;
	RakNetStatisticsStruct *rss;
	unsigned packetOrigin;

	// Used to refer to systems.  We already know the IP
	serverID.binaryAddress=inet_addr("127.0.0.1");
	serverID.port=60000;

	printf("Dropped Connection Test.\n");
	

	server=RakNetworkFactory::GetRakPeerInterface();
//	server->InitializeSecurity(0,0,0,0);
	server->Initialize(NUMBER_OF_CLIENTS, 60000, 0);
	server->SetMaximumIncomingConnections(NUMBER_OF_CLIENTS);

	for (index=0; index < NUMBER_OF_CLIENTS; index++)
	{
		clients[index]=RakNetworkFactory::GetRakPeerInterface();
		clients[index]->Initialize(1,60001+index,0);
		clients[index]->Connect("127.0.0.1", 60000, 0, 0);

		#ifdef _WIN32
				Sleep(10);
		#else
				usleep(10 * 1000);
		#endif
		printf("%i. ", index);
	}

	ShowHelp();

	while (1)
	{
		// User input
		if (kbhit())
		{
			ch=getch();

			if (ch=='d' || ch=='D')
			{
				index = randomMT() % NUMBER_OF_CLIENTS;
				
				clients[index]->GetConnectionList(0, &numberOfSystems);
				clients[index]->CloseConnection(serverID, false,0);
				if (numberOfSystems==0)
					printf("Client %i silently closing inactive connection.\n",index);
				else
					printf("Client %i silently closing active connection.\n",index);
			}
			else if (ch=='c' || ch=='C')
			{
				index = randomMT() % NUMBER_OF_CLIENTS;

				clients[index]->GetConnectionList(0, &numberOfSystems);
				clients[index]->Connect("127.0.0.1", 60000, 0, 0);
				if (numberOfSystems==0)
					printf("Client %i connecting to same existing connection.\n",index);
				else
					printf("Client %i connecting to closed connection.\n",index);
			}
			else if (ch=='r' || ch=='R' || ch=='n' || ch=='N')
			{
				printf("Randomly connecting and disconnecting each client\n");
				for (index=0; index < NUMBER_OF_CLIENTS; index++)
				{
					if ((randomMT()%2)==0)
					{
						if (clients[index]->IsActive())
						{
							if (ch=='r' || ch=='R')
								clients[index]->CloseConnection(serverID, false, 0);
							else
								clients[index]->CloseConnection(serverID, true, 100);
						}
					}
					else
					{
						clients[index]->Connect("127.0.0.1", 60000, 0, 0);
					}
				}
			}
			else if (ch==' ')
			{
				server->GetConnectionList(0, &numberOfSystems);
				printf("The server thinks %i clients are connected.\n", numberOfSystems);
				connectionCount=0;
				for (index=0; index < NUMBER_OF_CLIENTS; index++)
				{
					clients[index]->GetConnectionList(0, &numberOfSystems);
					if (numberOfSystems>1)
						printf("Bug: Client %i has %i connections\n", index, numberOfSystems);
					if (numberOfSystems==1)
					{
						connectionCount++;
					}
				}
				printf("%i clients are actually connected.\n", connectionCount);
			}
			else if (ch=='h' || ch=='H')
			{
				ShowHelp();
			}
			else if (ch=='q' || ch=='Q')
			{
				break;
			}
			ch=0;
		}

		// Parse messages
		
		while (1)
		{
			packetOrigin=65535;
			p = server->Receive();
			if (p==0)
			{
				for (index=0; index < NUMBER_OF_CLIENTS; index++)
				{
					p = clients[index]->Receive();
					if (p!=0)
					{
						packetOrigin=index;
						break;						
					}
				}
			}

			if (p)
			{
				switch (p->data[0])
				{
				case ID_CONNECTION_REQUEST_ACCEPTED:
					printf("%i: ID_CONNECTION_REQUEST_ACCEPTED.\n",packetOrigin);
					break;
				case ID_DISCONNECTION_NOTIFICATION:
					// Connection lost normally
					printf("%i: ID_DISCONNECTION_NOTIFICATION.\n",packetOrigin);
					break;

				case ID_NEW_INCOMING_CONNECTION:
					// Somebody connected.  We have their IP now
					printf("%i: ID_NEW_INCOMING_CONNECTION.\n",packetOrigin);
					break;

				case ID_RECEIVED_STATIC_DATA:
					// Got static data
					printf("%i: ID_RECEIVED_STATIC_DATA.\n",packetOrigin);
					break;

				case ID_MODIFIED_PACKET:
					// Cheater!
					printf("%i: ID_MODIFIED_PACKET.\n",packetOrigin);
					break;

				case ID_CONNECTION_LOST:
					// Couldn't deliver a reliable packet - i.e. the other system was abnormally
					// terminated
					printf("%i: ID_CONNECTION_LOST.\n",packetOrigin);
					break;
				default:
					// Ignore anything else
					break;
				}
			}
			else
				break;

			if (packetOrigin==65535)
				server->DeallocatePacket(p);
			else
				clients[packetOrigin]->DeallocatePacket(p);
		}

		// Have everyone send a reliable packet so dropped connections are noticed.
		ch=255;
		server->Send((char*)&ch, 1, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_PLAYER_ID, true);

		for (index=0; index < NUMBER_OF_CLIENTS; index++)
			clients[index]->Send((char*)&ch, 1, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_PLAYER_ID, true);

		// Sleep so this loop doesn't take up all the CPU time

#ifdef _WIN32
			Sleep(30);
#else
			usleep(30 * 1000);
#endif

	}

	RakNetworkFactory::DestroyRakPeerInterface(server);
	for (index=0; index < NUMBER_OF_CLIENTS; index++)
		RakNetworkFactory::DestroyRakPeerInterface(clients[index]);
	return 1;
}