예제 #1
0
Client* ClientConnectionSet::Add(LPSOCKADDR_IN addr)
{
    int newclientnum;

    // Get a random uniq client number
    Client* testclient;
    do
    {
        newclientnum = psserver->rng->Get(0x8fffff); //make clientnum random
        testclient = FindAny(newclientnum);
    }
    while(testclient != NULL);

    // Have uniq client number, create the new client
    Client* client = new Client();
    if(!client->Initialize(addr, newclientnum))
    {
        Bug1("Client Init failed?!?\n");
        delete client;
        return NULL;
    }

    CS::Threading::RecursiveMutexScopedLock lock(mutex);
    addrHash.PutUnique(SockAddress(client->GetAddress()), client);
    hash.Put(client->GetClientNum(), client);
    return client;
}
예제 #2
0
void ClientsManager::run(void)
{
	//Make sure the thread stays running
	while (!threadShouldExit())//as long as the thread should stay running
	{
		if (indexpointer <= -1)
		{
			juce::Thread::yield();//give some more time back to other threads before processing clients again

			lockProcess->enterRead();//make sure size() is properly readable

			maxsize = clientslist->size();//Let's see if there is anything to process
			
			lockProcess->exitRead();//Reading is done, no need to keep it mutex locked

			if (maxsize <= 0)//No clients...
			{
				juce::Thread::sleep(1);//no clients, wait 1 millisecond
			}
			else//We have clients to process!
			{
				//possibly initialise codes before client looping starts?
				laststamp = juce::Time::currentTimeMillis();

				//assign indexpointer to last client
				indexpointer = (maxsize - 1);
			}
		}
		else //There are clients to process as long indexpointer >= 0
		{
			lockProcess->enterWrite();//lock the clientslist so this client pointer doesn't magically dissappear

			maxsize = clientslist->size();//Let's see if the next client didn't suddenly dissappear

			if (indexpointer >= maxsize)//The wanted index is not set..
			{
				indexpointer = (maxsize - 1);//take the last used index and use that one instead
			}

			//Get client
			Client* c = clientslist->getUnchecked(indexpointer);

			int currentindex = indexpointer;

			//move to next client next iteration or if process is somehow interrupted
			--indexpointer;

			//process the client..

			if (c->IsConnectionStateExpired(laststamp))
			{
				if (c->CheckIfDisconnected())
				{
					c->MarkForDeletion();
				}
			}

			if (c->IsMarkedForDeletion())
			{
				c->Disconnect();

				if (serverprocessor != NULL)//special exception for server functions
				{
					serverprocessor->ClientWasRemoved(c);
				}

				#ifdef FEEDBACK_CLIENTSMANAGER_REMOVED_CLIENTS

					juce::String message("Client `");

					const std::string* clientname = c->GetClientName();

					if (clientname->length() > 0)//if name is set
					{
						message += *clientname;
					}
					else
					{
						message += CLIENT_UNKNOWN_NAME_TEXT;
					}
					
					message += "` (";

					message += *c->GetAddress();
					message += ':';
					message += *c->GetPort();
					message += ") disconnected";

					//possibly a switch case is needed here, for windows vs mac vs linux
					message += '\n';//newline

					std::cout << message;

				#endif
				
				arraylock.enter();
				clientslist->remove(currentindex, true);
				arraylock.exit();
			}
			else
			{
				/*
					Here, a mechanic could be added to stop execution time of thread after client processing time.
					If time exceeds the time threshol, restart thread.
				*/

				//process incoming data
				c->ProcessBuffers();

				//check if there is data to process
				if (c->HasBufferedCommunicationObjects())
				{
					juce::OwnedArray<CommunicationObject>* messages = c->GetBufferedCommunicationObjects();

					for (int i = (messages->size() - 1); i >= 0; i--)
					{
						CommunicationObject* message = messages->getUnchecked(i);
						messages->remove(i, false);

						/*
							std::cout << "TEST: " << message->ToString(c->GetLastClassPresentationProtocol()) << std::endl;
						*/

						CommunicationObjectType* devicename = message->ClearDataIndex(0);

						if (devicename != NULL)
						{
							juce::juce_wchar type = devicename->GetType();

							if (type == 's' || type == 'S' || type == 'A')
							{
								char* devicenamecharpointer = (char*)devicename->GetRawDataCopy();
								juce::String devicenamestring(devicenamecharpointer);
								delete devicenamecharpointer;
								delete devicename;

								switch (devicenamestring[0])//this message is meant for a group
								{
									case '#':
									{
										devicenamestring = devicenamestring.substring(1);
										if (serverprocessor != NULL)//special exception for server functions
										{
											if (devicenamestring.equalsIgnoreCase("server"))
											{		
												serverprocessor->ProcesssFunction(c, message);
												continue;
											}
										}
										
										//a group of clients
										{
											if (c->IsFullyIdentified())//only clients that are identified are allowed to do this
											{
												const std::string* this_clientname = c->GetClientName();
												message->ReplaceDataIndex(0, new CommunicationObjectType(*this_clientname));

												for (int u = (maxsize - 1); u >= 0; u--)//and iterate backwards
												{
													Client* t = clientslist->getUnchecked(u);

													if (t != c && t->IsFullyIdentified())//do not self to self and target must be identified
													{
														if (!t->MarkedSenderOnly() && t->IsClientPartOfGroup(devicenamestring))
														{
															t->Send(message);
														}
													}
												}
											}
										}
										break;//#
									}
									case '?'://meant for every client (send message to every client)
									{
										if (c->IsFullyIdentified())//only clients that are identified are allowed to do this
										{
											const std::string* this_clientname = c->GetClientName();
											message->ReplaceDataIndex(0, new CommunicationObjectType(*this_clientname));

											for (int u = (maxsize - 1); u >= 0; u--)//and iterate backwards
											{
												Client* t = clientslist->getUnchecked(u);
												if (!t->MarkedSenderOnly() && t != c)//do not send to self
												{
													t->Send(message);
												}
											}
										}
										break;//?
									}
									case '!'://meant for every registered client (send message to every registered client)
									{
										if (c->IsFullyIdentified())//only clients that are identified are allowed to do this
										{
											const std::string* this_clientname = c->GetClientName();
											message->ReplaceDataIndex(0, new CommunicationObjectType(*this_clientname));

											for (int u = (maxsize - 1); u >= 0; u--)//and iterate backwards
											{
												Client* t = clientslist->getUnchecked(u);
												if (!t->MarkedSenderOnly() && t != c && t->IsFullyIdentified())//do not send to self
												{
													t->Send(message);
												}
											}
										}
										break;//!
									}
									default://compare name
									{
										if (c->IsFullyIdentified())//only clients that are identified are allowed to do this
										{
											const std::string* this_clientname = c->GetClientName();
											message->ReplaceDataIndex(0, new CommunicationObjectType(*this_clientname));

											for (int u = (maxsize - 1); u >= 0; u--)//and iterate backwards
											{
												Client* t = clientslist->getUnchecked(u);

												if (!t->MarkedSenderOnly() && t != c && t->IsFullyIdentified())//do not self to self and target must be identified
												{
													if (devicenamestring.compareNatural(juce::StringRef(*t->GetClientName())))
													{
														t->Send(message);
														break;
													}
												}
											}
										}
										break;
									}
								}
							}
							else
							{
								delete devicename;
							}
						}

						delete message;
					}

					messages->clear(false);
					delete messages;
					//messages = NULL;
				}
			}

			lockProcess->exitWrite();//unlock mutex

			//Give other threads more processing time by yielding after X time

			//The following algorithm checks whether the amount of clients superseeds or underseeds the load processing
			//If there are many clients, the yield will happen less often
			if (++AdaptiveLoad_CurrentBatchSizeClientProcessing >= AdaptiveLoad_BatchSizeClientProcessing)
			{
				//after processing X clients, reset counter so yielding won't happen immediately after
				AdaptiveLoad_CurrentBatchSizeClientProcessing = 0;

				if (maxsize - AdaptiveLoad_BatchSizeClientProcessing > AdaptiveLoad_HeavyLoadNumClientsThreshhold)//if is bigger
				{
					AdaptiveLoad_BatchSizeClientProcessing += AdaptiveLoad_HeavyLoadNumClientsThreshhold;
				}
				else if (AdaptiveLoad_BatchSizeClientProcessing - maxsize > AdaptiveLoad_HeavyLoadNumClientsThreshhold)
				{
					AdaptiveLoad_BatchSizeClientProcessing -= AdaptiveLoad_HeavyLoadNumClientsThreshhold;

					if (AdaptiveLoad_BatchSizeClientProcessing < AdaptiveLoad_HeavyLoadNumClientsThreshhold)
					{
						AdaptiveLoad_BatchSizeClientProcessing = AdaptiveLoad_HeavyLoadNumClientsThreshhold;//make sure at least some clients are processed
					}
				}

				juce::Thread::yield();//yield once to provide an additional time slice for other threads
			}
		}
	}
}