1 // ==============================================================
2 //	This file is part of Glest (www.glest.org)
3 //
4 //	Copyright (C) 2001-2008 Martiño Figueroa
5 //
6 //	You can redistribute this code and/or modify it under
7 //	the terms of the GNU General Public License as published
8 //	by the Free Software Foundation; either version 2 of the
9 //	License, or (at your option) any later version
10 // ==============================================================
11 
12 #include "server_interface.h"
13 
14 #include <stdexcept>
15 
16 #include "window.h"
17 #include "logger.h"
18 
19 #include "platform_util.h"
20 #include "conversion.h"
21 #include "config.h"
22 #include "lang.h"
23 #include "util.h"
24 #include "game_util.h"
25 #include "miniftpserver.h"
26 #include "map_preview.h"
27 #include "stats.h"
28 #include <time.h>
29 #include <set>
30 #include <iostream>
31 #include <iterator>
32 
33 #include "leak_dumper.h"
34 
35 using namespace std;
36 using namespace Shared::Platform;
37 using namespace Shared::Util;
38 using namespace Shared::Map;
39 
40 namespace Glest { namespace Game {
41 
42 double maxFrameCountLagAllowed 								= 30;
43 double maxClientLagTimeAllowed 								= 25;
44 double maxFrameCountLagAllowedEver 							= 30;
45 double maxClientLagTimeAllowedEver							= 25;
46 
47 double warnFrameCountLagPercent 							= 0.50;
48 double LAG_CHECK_GRACE_PERIOD 								= 15;
49 double LAG_CHECK_INTERVAL_PERIOD 							= 4;
50 
51 const int MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS	= 15000;
52 const int MAX_CLIENT_PAUSE_FOR_LAG_COUNT					= 3;
53 const int MAX_SLOT_THREAD_WAIT_TIME_MILLISECONDS			= 1500;
54 const int MASTERSERVER_HEARTBEAT_GAME_STATUS_SECONDS 		= 30;
55 
56 const int MAX_EMPTY_NETWORK_COMMAND_LIST_BROADCAST_INTERVAL_MILLISECONDS = 4000;
57 
ServerInterface(bool publishEnabled,ClientLagCallbackInterface * clientLagCallbackInterface)58 ServerInterface::ServerInterface(bool publishEnabled, ClientLagCallbackInterface *clientLagCallbackInterface) : GameNetworkInterface() {
59 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
60 
61 	this->clientLagCallbackInterface	= clientLagCallbackInterface;
62 	this->clientsAutoPausedDueToLag     = false;
63 
64 	allowInGameConnections 				= false;
65 	gameLaunched 						= false;
66 
67 	serverSynchAccessor 				= new Mutex(CODE_AT_LINE);
68 	switchSetupRequestsSynchAccessor 	= new Mutex(CODE_AT_LINE);
69 
70 	for(int index = 0; index < GameConstants::maxPlayers; ++index) {
71 		slotAccessorMutexes[index] 		= new Mutex(CODE_AT_LINE);
72 	}
73 	masterServerThreadAccessor 			= new Mutex(CODE_AT_LINE);
74 	textMessageQueueThreadAccessor 		= new Mutex(CODE_AT_LINE);
75 	broadcastMessageQueueThreadAccessor = new Mutex(CODE_AT_LINE);
76 	inBroadcastMessageThreadAccessor 	= new Mutex(CODE_AT_LINE);
77 
78 	serverSocketAdmin				= NULL;
79 	nextEventId 					= 1;
80 	gameHasBeenInitiated 			= false;
81 	exitServer 						= false;
82 	gameSettingsUpdateCount 		= 0;
83 	currentFrameCount 				= 0;
84 	gameStartTime 					= 0;
85 	resumeGameStartTime				= 0;
86 	publishToMasterserverThread 	= NULL;
87 	lastMasterserverHeartbeatTime 	= 0;
88 	needToRepublishToMasterserver 	= false;
89 	ftpServer 						= NULL;
90 	inBroadcastMessage				= false;
91 	lastGlobalLagCheckTime			= 0;
92 	masterserverAdminRequestLaunch	= false;
93 	lastListenerSlotCheckTime		= 0;
94 
95 	// This is an admin port listening only on the localhost intended to
96 	// give current connection status info
97 #ifndef __APPLE__
98 	try {
99 		serverSocketAdmin			= new ServerSocket(true);
100 		serverSocketAdmin->setBlock(false);
101 		serverSocketAdmin->setBindPort(Config::getInstance().getInt("ServerAdminPort", intToStr(GameConstants::serverAdminPort).c_str()));
102 		serverSocketAdmin->setBindSpecificAddress(Config::getInstance().getString("ServerAdminBindAddress", "127.0.0.1"));
103 		serverSocketAdmin->listen(5);
104 	}
105 	catch(const std::exception &ex) {
106 		char szBuf[8096]="";
107 		snprintf(szBuf,8096,"In [%s::%s Line: %d] Warning Server admin port bind/listen error:\n%s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
108 		SystemFlags::OutputDebug(SystemFlags::debugError,szBuf);
109 
110 		if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"%s",szBuf);
111 	}
112 #endif
113 
114 	maxFrameCountLagAllowed 				= Config::getInstance().getInt("MaxFrameCountLagAllowed", intToStr(maxFrameCountLagAllowed).c_str());
115 	maxFrameCountLagAllowedEver 			= Config::getInstance().getInt("MaxFrameCountLagAllowedEver", intToStr(maxFrameCountLagAllowedEver).c_str());
116 	maxClientLagTimeAllowedEver				= Config::getInstance().getInt("MaxClientLagTimeAllowedEver", intToStr(maxClientLagTimeAllowedEver).c_str());
117 	maxClientLagTimeAllowed 				= Config::getInstance().getInt("MaxClientLagTimeAllowed", intToStr(maxClientLagTimeAllowed).c_str());
118 	warnFrameCountLagPercent 				= Config::getInstance().getFloat("WarnFrameCountLagPercent", doubleToStr(warnFrameCountLagPercent).c_str());
119 
120 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] maxFrameCountLagAllowed = %f, maxFrameCountLagAllowedEver = %f, maxClientLagTimeAllowed = %f, maxClientLagTimeAllowedEver = %f\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,maxFrameCountLagAllowed,maxFrameCountLagAllowedEver,maxClientLagTimeAllowed,maxClientLagTimeAllowedEver);
121 
122 	for(int index = 0; index < GameConstants::maxPlayers; ++index) {
123 		slots[index]				= NULL;
124 		switchSetupRequests[index]	= NULL;
125 	}
126 
127 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
128 
129 	serverSocket.setBlock(false);
130 	serverSocket.setBindPort(Config::getInstance().getInt("PortServer", intToStr(GameConstants::serverPort).c_str()));
131 
132 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
133 
134 	gameStatsThreadAccessor 	= new Mutex(CODE_AT_LINE);
135 	gameStats 					= NULL;
136 
137 	Config &config 			= Config::getInstance();
138   	string scenarioDir 		= "";
139   	vector<string> pathList = config.getPathListForType(ptMaps,scenarioDir);
140   	vector<string> invalidMapList;
141   	vector<string> allMaps = MapPreview::findAllValidMaps(pathList,scenarioDir,false,true,&invalidMapList);
142 	if (allMaps.empty()) {
143         //throw megaglest_runtime_error("No maps were found!");
144 		printf("No maps were found (srv)!\n");
145 	}
146 	std::sort(allMaps.begin(),allMaps.end(),compareNonCaseSensitive);
147 	vector<string> results;
148 	copy(allMaps.begin(), allMaps.end(), std::back_inserter(results));
149 	mapFiles = results;
150 
151 	//player Sorted maps
152 	////////////////////
153 	for(unsigned int i = 0; i < GameConstants::maxPlayers+1; ++i) {
154 		playerSortedMaps[i].clear();
155 	}
156 
157 	// at index=0 fill in the whole list
158 	copy(mapFiles.begin(), mapFiles.end(), std::back_inserter(playerSortedMaps[0]));
159 
160 	MapInfo mapInfo;
161 	// fill playerSortedMaps according to map player count
162 	for(int i= 0; i < (int)mapFiles.size(); i++){// fetch info and put map in right list
163 		//printf("mapFiles.at(i) %s allMaps.at[i] %s\n",mapFiles[i].c_str(),allMaps.at(i).c_str());
164 		MapPreview::loadMapInfo(Config::getMapPath(mapFiles.at(i)), &mapInfo, "MaxPlayers","Size",true) ;
165 		playerSortedMaps[mapInfo.players].push_back(mapFiles.at(i));
166 	}
167 	///////////////////
168 
169 	results.clear();
170     findDirs(config.getPathListForType(ptTilesets), results);
171 	if (results.empty()) {
172         //throw megaglest_runtime_error("No tile-sets were found!");
173 		printf("No tile-sets were found (srv)!");
174 	}
175     tilesetFiles = results;
176 
177     results.clear();
178     findDirs(config.getPathListForType(ptTechs), results);
179 	if(results.empty()) {
180         //throw megaglest_runtime_error("No tech-trees were found!");
181 		printf("No tech-trees were found (srv)!\n");
182 	}
183     techTreeFiles = results;
184 
185 	if(Config::getInstance().getBool("EnableFTPServer","true") == true) {
186 		std::pair<string,string> mapsPath;
187 		vector<string> pathList = Config::getInstance().getPathListForType(ptMaps);
188 		if(pathList.empty() == false) {
189 			mapsPath.first = pathList[0];
190 			if(pathList.size() > 1) {
191 				mapsPath.second = pathList[1];
192 			}
193 		}
194 
195 		std::pair<string,string> tilesetsPath;
196 		vector<string> tilesetsList = Config::getInstance().getPathListForType(ptTilesets);
197 		if(tilesetsList.empty() == false) {
198 			tilesetsPath.first = tilesetsList[0];
199 			if(tilesetsList.size() > 1) {
200 				tilesetsPath.second = tilesetsList[1];
201 			}
202 		}
203 
204 		std::pair<string,string> techtreesPath;
205 		vector<string> techtreesList = Config::getInstance().getPathListForType(ptTechs);
206 		if(techtreesList.empty() == false) {
207 			techtreesPath.first = techtreesList[0];
208 			if(techtreesList.size() > 1) {
209 				techtreesPath.second = techtreesList[1];
210 			}
211 		}
212 
213 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
214 		int portNumber   = Config::getInstance().getInt("FTPServerPort",intToStr(ServerSocket::getFTPServerPort()).c_str());
215 		ServerSocket::setFTPServerPort(portNumber);
216 		//printf("In [%s::%s] portNumber = %d ServerSocket::getFTPServerPort() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,portNumber,ServerSocket::getFTPServerPort());
217 
218 		bool allowInternetTilesetFileTransfers = Config::getInstance().getBool("EnableFTPServerInternetTilesetXfer","true");
219 		bool allowInternetTechtreeFileTransfers = Config::getInstance().getBool("EnableFTPServerInternetTechtreeXfer","true");
220 
221 		// Get path to temp files
222 		string tempFilePath = "temp/";
223 		if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
224 			tempFilePath = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + tempFilePath;
225 		}
226 		else {
227 	        string userData = config.getString("UserData_Root","");
228 	        if(userData != "") {
229 	        	endPathWithSlash(userData);
230 	        }
231 	        tempFilePath = userData + tempFilePath;
232 		}
233 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Temp files path [%s]\n",tempFilePath.c_str());
234 
235 		ftpServer = new FTPServerThread(mapsPath,tilesetsPath,techtreesPath,
236 				publishEnabled,allowInternetTilesetFileTransfers,
237 				allowInternetTechtreeFileTransfers,portNumber,GameConstants::maxPlayers,
238 				this,tempFilePath);
239 		ftpServer->start();
240 	}
241 
242 	if(publishToMasterserverThread == NULL) {
243 		if(needToRepublishToMasterserver == true || GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
244 			static string mutexOwnerId = string(extractFileFromDirectoryPath(__FILE__).c_str()) + string("_") + intToStr(__LINE__);
245 			publishToMasterserverThread = new SimpleTaskThread(this,0,125);
246 			publishToMasterserverThread->setUniqueID(mutexOwnerId);
247 			publishToMasterserverThread->start();
248 
249 			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] needToRepublishToMasterserver = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,needToRepublishToMasterserver);
250 		}
251 	}
252 
253 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
254 }
255 
setPublishEnabled(bool value)256 void ServerInterface::setPublishEnabled(bool value) {
257 	if(ftpServer != NULL) {
258 		ftpServer->setInternetEnabled(value);
259 	}
260 }
261 
shutdownMasterserverPublishThread()262 void ServerInterface::shutdownMasterserverPublishThread() {
263 	MutexSafeWrapper safeMutex(masterServerThreadAccessor,CODE_AT_LINE);
264 
265 	if(publishToMasterserverThread != NULL) {
266 		time_t elapsed = time(NULL);
267 		publishToMasterserverThread->signalQuit();
268 		for(;publishToMasterserverThread->canShutdown(false) == false &&
269 			difftime((long int)time(NULL),elapsed) <= 15;) {
270 			//sleep(150);
271 		}
272 		if(publishToMasterserverThread->canShutdown(true)) {
273 			delete publishToMasterserverThread;
274 			publishToMasterserverThread = NULL;
275 		}
276 	}
277 }
278 
~ServerInterface()279 ServerInterface::~ServerInterface() {
280 	//printf("===> Destructor for ServerInterface\n");
281 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
282 
283 	masterController.clearSlaves(true);
284 	exitServer = true;
285 	for(int index = 0; index < GameConstants::maxPlayers; ++index) {
286 		if(slots[index] != NULL) {
287 			MutexSafeWrapper safeMutex(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
288 			delete slots[index];
289 			slots[index] = NULL;
290 		}
291 
292 		if(switchSetupRequests[index] != NULL) {
293 			delete switchSetupRequests[index];
294 			switchSetupRequests[index] = NULL;
295 		}
296 	}
297 
298 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
299 	close();
300 	shutdownFTPServer();
301 	shutdownMasterserverPublishThread();
302 
303 	lastMasterserverHeartbeatTime = 0;
304 	if(needToRepublishToMasterserver == true) {
305 		simpleTask(NULL,NULL);
306 	}
307 
308 	for(int index = 0; index < GameConstants::maxPlayers; ++index) {
309 		delete slotAccessorMutexes[index];
310 		slotAccessorMutexes[index] = NULL;
311 	}
312 
313 	delete textMessageQueueThreadAccessor;
314 	textMessageQueueThreadAccessor = NULL;
315 
316 	delete broadcastMessageQueueThreadAccessor;
317 	broadcastMessageQueueThreadAccessor = NULL;
318 
319 	delete inBroadcastMessageThreadAccessor;
320 	inBroadcastMessageThreadAccessor = NULL;
321 
322 	delete serverSynchAccessor;
323 	serverSynchAccessor = NULL;
324 
325 	delete masterServerThreadAccessor;
326 	masterServerThreadAccessor = NULL;
327 
328 	delete serverSocketAdmin;
329 	serverSocketAdmin = NULL;
330 
331 	for(int index = 0; index < (int)broadcastMessageQueue.size(); ++index) {
332 		pair<NetworkMessage *,int> &item = broadcastMessageQueue[index];
333 		if(item.first != NULL) {
334 			delete item.first;
335 		}
336 		item.first = NULL;
337 	}
338 	broadcastMessageQueue.clear();
339 
340 	delete switchSetupRequestsSynchAccessor;
341 	switchSetupRequestsSynchAccessor = NULL;
342 
343 	delete gameStatsThreadAccessor;
344 	gameStatsThreadAccessor = NULL;
345 
346 	delete gameStats;
347 	gameStats = NULL;
348 
349 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
350 }
351 
getSwitchSetupRequests()352 SwitchSetupRequest ** ServerInterface::getSwitchSetupRequests() {
353 	MutexSafeWrapper safeMutex(switchSetupRequestsSynchAccessor,CODE_AT_LINE);
354     return &switchSetupRequests[0];
355 }
356 
getSwitchSetupRequests(int index)357 SwitchSetupRequest * ServerInterface::getSwitchSetupRequests(int index) {
358 	MutexSafeWrapper safeMutex(switchSetupRequestsSynchAccessor,CODE_AT_LINE);
359     return switchSetupRequests[index];
360 }
361 
setSwitchSetupRequests(int index,SwitchSetupRequest * ptr)362 void ServerInterface::setSwitchSetupRequests(int index,SwitchSetupRequest *ptr) {
363 	MutexSafeWrapper safeMutex(switchSetupRequestsSynchAccessor,CODE_AT_LINE);
364     switchSetupRequests[index] = ptr;
365 }
366 
isValidClientType(uint32 clientIp)367 int ServerInterface::isValidClientType(uint32 clientIp) {
368 	int result = 0;
369 	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
370 		MutexSafeWrapper safeMutex(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
371 		if(slots[index] != NULL) {
372 			Socket *socket = slots[index]->getSocket();
373 			if(socket != NULL) {
374 				uint32 slotIp = socket->getConnectedIPAddress(socket->getIpAddress());
375 				if(slotIp == clientIp) {
376 					result = 1;
377 					break;
378 				}
379 			}
380 		}
381 	}
382 	return result;
383 }
384 
isClientAllowedToGetFile(uint32 clientIp,const char * username,const char * filename)385 int ServerInterface::isClientAllowedToGetFile(uint32 clientIp, const char *username, const char *filename) {
386 	int result = 1;
387 
388 	if(	username != NULL &&
389 			strlen(username) > 0 &&
390 		filename != NULL &&
391 			strlen(filename) > 0) {
392 		string user = username;
393 		string file = filename;
394 
395 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d username [%s] file [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,username,filename);
396 
397 		if(StartsWith(user,"tilesets") == true && EndsWith(file,"7z") == false) {
398 			if(Config::getInstance().getBool("DisableFTPServerXferUncompressedTilesets","false") == true) {
399 				result = 0;
400 			}
401 			else {
402 				char szIP[100] = "";
403 				Ip::Inet_NtoA(clientIp,szIP);
404 				string clientIP = szIP;
405 				std::vector<std::string> serverList = Socket::getLocalIPAddressList();
406 
407 				result = 0;
408 				for(unsigned int index = 0; index < serverList.size(); ++index) {
409 					string serverIP = serverList[index];
410 
411 					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d clientIP [%s] serverIP [%s] %d / %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientIP.c_str(),serverIP.c_str(),index,serverList.size());
412 
413 					vector<string> clientTokens;
414 					Tokenize(clientIP,clientTokens,".");
415 
416 					vector<string> serverTokens;
417 					Tokenize(serverIP,serverTokens,".");
418 
419 					if(clientTokens.size() == 4 && serverTokens.size() == 4) {
420 						if( clientTokens[0] == serverTokens[0] ||
421 							clientTokens[1] == serverTokens[1] ||
422 							clientTokens[2] == serverTokens[2]) {
423 							result = 1;
424 
425 							if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d clientIP [%s] IS NOT BLOCKED\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientIP.c_str());
426 
427 							break;
428 						}
429 					}
430 				}
431 			}
432 		}
433 	}
434 	return result;
435 }
436 
addClientToServerIPAddress(uint32 clientIp,uint32 ServerIp)437 void ServerInterface::addClientToServerIPAddress(uint32 clientIp, uint32 ServerIp) {
438 	FTPServerThread::addClientToServerIPAddress(clientIp, ServerIp);
439 }
440 
addSlot(int playerIndex)441 void ServerInterface::addSlot(int playerIndex) {
442 	//printf("Adding slot for playerIndex = %d, serverSocket.isPortBound() = %d\n",playerIndex,serverSocket.isPortBound());
443 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
444 
445 	if(playerIndex < 0 || playerIndex >= GameConstants::maxPlayers) {
446 		char szBuf[8096]="";
447 		snprintf(szBuf,8096,"In [%s::%s %d] playerIndex is invalid = %d",extractFileFromDirectoryPath(extractFileFromDirectoryPath(__FILE__).c_str()).c_str(),__FUNCTION__,__LINE__,playerIndex);
448 		throw megaglest_runtime_error(szBuf);
449 	}
450 	MutexSafeWrapper safeMutex(serverSynchAccessor,CODE_AT_LINE);
451 	if(serverSocketAdmin != NULL && serverSocketAdmin->isSocketValid() == false) {
452 		serverSocketAdmin->listen(5);
453 	}
454 	if(serverSocket.isPortBound() == false) {
455 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
456 		serverSocket.bind(serverSocket.getBindPort());
457 	}
458 
459 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
460 
461 	MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[playerIndex],CODE_AT_LINE_X(playerIndex));
462 
463 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
464 
465 	ConnectionSlot *slot = slots[playerIndex];
466 	if(slot != NULL) {
467 		slots[playerIndex] = NULL;
468 	}
469 	slots[playerIndex] = new ConnectionSlot(this, playerIndex);
470 
471 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
472 
473 	safeMutexSlot.ReleaseLock();
474 	delete slot;
475 
476 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
477 
478 	safeMutex.ReleaseLock();
479 
480 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
481 
482 	updateListen();
483 
484 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
485 }
486 
removeSlot(int playerIndex,int lockedSlotIndex)487 void ServerInterface::removeSlot(int playerIndex, int lockedSlotIndex) {
488 	//printf("Removing slot for playerIndex = %d, serverSocket.isPortBound() = %d\n",playerIndex,serverSocket.isPortBound());
489 
490 	if(playerIndex < 0 || playerIndex >= GameConstants::maxPlayers) {
491 		char szBuf[8096]="";
492 		snprintf(szBuf,8096,"In [%s::%s %d] playerIndex is invalid = %d",extractFileFromDirectoryPath(extractFileFromDirectoryPath(__FILE__).c_str()).c_str(),__FUNCTION__,__LINE__,playerIndex);
493 		throw megaglest_runtime_error(szBuf);
494 	}
495 
496 	Lang &lang= Lang::getInstance();
497 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
498 
499 	MutexSafeWrapper safeMutex(serverSynchAccessor,CODE_AT_LINE);
500 	MutexSafeWrapper safeMutexSlot(NULL,CODE_AT_LINE_X(playerIndex));
501 	if(playerIndex != lockedSlotIndex) {
502 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
503 		safeMutexSlot.setMutex(slotAccessorMutexes[playerIndex],CODE_AT_LINE_X(playerIndex));
504 	}
505 
506 	vector<string> msgList;
507 	ConnectionSlot *slot 				= slots[playerIndex];
508 	bool notifyDisconnect 				= false;
509 	const vector<string> languageList 	= this->gameSettings.getUniqueNetworkPlayerLanguages();
510 	if(slot != NULL) {
511 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
512 
513 		if(slot->getLastReceiveCommandListTime() > 0) {
514 			char szBuf[4096] = "";
515 
516 			for(unsigned int index = 0; index < languageList.size(); ++index) {
517 				string msgTemplate = "Player %s, disconnected from the game.";
518 				if(lang.hasString("PlayerDisconnected",languageList[index]) == true) {
519 					msgTemplate = lang.getString("PlayerDisconnected",languageList[index]);
520 				}
521 #ifdef WIN32
522 				_snprintf(szBuf,4095,msgTemplate.c_str(),slot->getName().c_str());
523 #else
524 				snprintf(szBuf,4095,msgTemplate.c_str(),slot->getName().c_str());
525 #endif
526 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,szBuf);
527 
528 				msgList.push_back(szBuf);
529 			}
530 
531 			notifyDisconnect = true;
532 		}
533 	}
534 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
535 
536 	slots[playerIndex]= NULL;
537 	safeMutexSlot.ReleaseLock();
538 	safeMutex.ReleaseLock();
539 
540 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
541 
542 	if(slot != NULL) slot->close();
543 	delete slot;
544 
545 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
546 
547 	updateListen();
548 
549 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
550 
551 	if(notifyDisconnect == true) {
552 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
553 
554 		for(unsigned int index = 0; index < languageList.size(); ++index) {
555 			bool localEcho = lang.isLanguageLocal(languageList[index]);
556 			queueTextMessage(msgList[index],-1, localEcho, languageList[index]);
557 		}
558 	}
559 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,playerIndex,lockedSlotIndex);
560 }
561 
switchSlot(int fromPlayerIndex,int toPlayerIndex)562 bool ServerInterface::switchSlot(int fromPlayerIndex, int toPlayerIndex) {
563 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
564 	bool result = false;
565 
566 	//printf("#1 Server is switching slots\n");
567 
568 	if(fromPlayerIndex < 0 || fromPlayerIndex >= GameConstants::maxPlayers) {
569 		char szBuf[8096]="";
570 		snprintf(szBuf,8096,"In [%s::%s %d] fromPlayerIndex is invalid = %d",extractFileFromDirectoryPath(extractFileFromDirectoryPath(__FILE__).c_str()).c_str(),__FUNCTION__,__LINE__,fromPlayerIndex);
571 		throw megaglest_runtime_error(szBuf);
572 	}
573 
574 	if(toPlayerIndex < 0 || toPlayerIndex >= GameConstants::maxPlayers) {
575 		char szBuf[8096]="";
576 		snprintf(szBuf,8096,"In [%s::%s %d] toPlayerIndex is invalid = %d",extractFileFromDirectoryPath(extractFileFromDirectoryPath(__FILE__).c_str()).c_str(),__FUNCTION__,__LINE__,toPlayerIndex);
577 		throw megaglest_runtime_error(szBuf);
578 	}
579 
580 	if(fromPlayerIndex == toPlayerIndex) {
581 		return false;
582 	}
583 
584 	MutexSafeWrapper safeMutex(serverSynchAccessor,CODE_AT_LINE);
585 	MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[fromPlayerIndex],CODE_AT_LINE_X(fromPlayerIndex));
586 	MutexSafeWrapper safeMutexSlot2(slotAccessorMutexes[toPlayerIndex],CODE_AT_LINE_X(toPlayerIndex));
587 
588 	//printf("#1a Server is switching slots\n");
589 
590 	if(slots[toPlayerIndex] != NULL &&
591 	   slots[toPlayerIndex]->hasValidSocketId() == false) {
592 
593 		//printf("#2 Server is switching slots\n");
594 
595 		slots[fromPlayerIndex]->setPlayerIndex(toPlayerIndex);
596 		slots[toPlayerIndex]->setPlayerIndex(fromPlayerIndex);
597 		ConnectionSlot *tmp 	= slots[toPlayerIndex];
598 		slots[toPlayerIndex] 	= slots[fromPlayerIndex];
599 		slots[fromPlayerIndex] 	= tmp;
600 
601 		safeMutex.ReleaseLock();
602 
603 		PlayerIndexMessage playerIndexMessage(toPlayerIndex);
604 		slots[toPlayerIndex]->sendMessage(&playerIndexMessage);
605 
606 		//slots[fromPlayerIndex]->resetJoinGameInProgressFlags();
607 		//slots[toPlayerIndex]->setJoinGameInProgressFlags();
608 
609 		safeMutexSlot.ReleaseLock();
610 		safeMutexSlot2.ReleaseLock();
611 		result = true;
612 		updateListen();
613 	}
614 	else {
615 		//printf("#3 Server is switching slots aborted, is slot already connected?\n");
616 
617 		safeMutexSlot.ReleaseLock();
618 		safeMutexSlot2.ReleaseLock();
619 		safeMutex.ReleaseLock();
620 	}
621 	//printf("#4 Server is switching slots\n");
622 
623 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
624 	return result;
625 }
626 
getSlotMutex(int playerIndex)627 Mutex *ServerInterface::getSlotMutex(int playerIndex) {
628 	return slotAccessorMutexes[playerIndex];
629 }
630 
getSlot(int playerIndex,bool lockMutex)631 ConnectionSlot *ServerInterface::getSlot(int playerIndex, bool lockMutex) {
632 	if(playerIndex < 0 || playerIndex >= GameConstants::maxPlayers) {
633 		char szBuf[8096]="";
634 		snprintf(szBuf,8096,"In [%s::%s %d] playerIndex is invalid = %d",extractFileFromDirectoryPath(extractFileFromDirectoryPath(__FILE__).c_str()).c_str(),__FUNCTION__,__LINE__,playerIndex);
635 		throw megaglest_runtime_error(szBuf);
636 	}
637 
638 	MutexSafeWrapper safeMutexSlot((lockMutex == true ? slotAccessorMutexes[playerIndex] : NULL),CODE_AT_LINE_X(playerIndex));
639 	ConnectionSlot *result = slots[playerIndex];
640 	return result;
641 }
642 
isClientConnected(int playerIndex)643 bool ServerInterface::isClientConnected(int playerIndex) {
644 	if(playerIndex < 0 || playerIndex >= GameConstants::maxPlayers) {
645 		char szBuf[8096]="";
646 		snprintf(szBuf,8096,"In [%s::%s %d] playerIndex is invalid = %d",extractFileFromDirectoryPath(extractFileFromDirectoryPath(__FILE__).c_str()).c_str(),__FUNCTION__,__LINE__,playerIndex);
647 		throw megaglest_runtime_error(szBuf);
648 	}
649 
650 	bool result = false;
651 	MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[playerIndex],CODE_AT_LINE_X(playerIndex));
652 	if(slots[playerIndex] != NULL && slots[playerIndex]->isConnected() == true) {
653 		result = true;
654 	}
655 	return result;
656 }
657 
hasClientConnection()658 bool ServerInterface::hasClientConnection() {
659 	bool result = false;
660 	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
661 		if(isClientConnected(index) == true) {
662 			result = true;
663 			break;
664 		}
665 	}
666 	return result;
667 }
668 
getSlotCount()669 int ServerInterface::getSlotCount() {
670 	int slotCount = 0;
671 	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
672 		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
673 		if(slots[index] != NULL) {
674 			++slotCount;
675 		}
676 	}
677 	return slotCount;
678 }
679 
getConnectedSlotCount(bool authenticated)680 int ServerInterface::getConnectedSlotCount(bool authenticated) {
681 	int connectedSlotCount = 0;
682 	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
683 		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
684 		if(slots[index] != NULL && slots[index]->isConnected() == true) {
685 			if(authenticated == false ||
686 				(authenticated == true && slots[index]->getConnectHasHandshaked() == true)) {
687 				++connectedSlotCount;
688 			}
689 		}
690 	}
691 	return connectedSlotCount;
692 }
693 
getNextEventId()694 int64 ServerInterface::getNextEventId() {
695 	nextEventId++;
696 	if(nextEventId > INT_MAX) {
697 		nextEventId = 1;
698 	}
699 	return nextEventId;
700 }
701 
clientLagCheck(ConnectionSlot * connectionSlot,bool skipNetworkBroadCast)702 std::pair<bool,bool> ServerInterface::clientLagCheck(ConnectionSlot *connectionSlot, bool skipNetworkBroadCast) {
703 	std::pair<bool,bool> clientLagExceededOrWarned = std::make_pair(false, false);
704 	static bool alreadyInLagCheck = false;
705 
706 	if(alreadyInLagCheck == true ||
707 		(connectionSlot != NULL && (connectionSlot->getSkipLagCheck() == true ||
708 		 connectionSlot->getConnectHasHandshaked() == false))) {
709 		return clientLagExceededOrWarned;
710 	}
711 
712 	try {
713 		alreadyInLagCheck = true;
714 
715 		if((gameStartTime > 0 &&
716 				difftime((long int)time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD) &&
717 			(resumeGameStartTime == 0 ||
718 			  (resumeGameStartTime > 0 &&
719 					  difftime((long int)time(NULL),resumeGameStartTime) >= LAG_CHECK_GRACE_PERIOD))) {
720 			if(connectionSlot != NULL && connectionSlot->isConnected() == true) {
721 
722 				double clientLag 		= this->getCurrentFrameCount() - connectionSlot->getCurrentFrameCount();
723 				double clientLagCount 	= (gameSettings.getNetworkFramePeriod() > 0 ? (clientLag / gameSettings.getNetworkFramePeriod()) : 0);
724 				connectionSlot->setCurrentLagCount(clientLagCount);
725 
726 				double clientLagTime 	= difftime((long int)time(NULL),connectionSlot->getLastReceiveCommandListTime());
727 
728 				if(this->getCurrentFrameCount() > 0) {
729 					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d, clientLag = %f, clientLagCount = %f, this->getCurrentFrameCount() = %d, connectionSlot->getCurrentFrameCount() = %d, clientLagTime = %f\n",
730 																		 extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,
731 																		 connectionSlot->getPlayerIndex(),
732 																		 clientLag,clientLagCount,
733 																		 this->getCurrentFrameCount(),
734 																		 connectionSlot->getCurrentFrameCount(),
735 																		 clientLagTime);
736 				}
737 
738 				// TEST LAG Error and warnings!!!
739 				//clientLagCount = maxFrameCountLagAllowed + 1;
740 				//clientLagTime = maxClientLagTimeAllowed + 1;
741 				/*
742 				if(difftime(time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD + 5) {
743 					clientLagTime = maxClientLagTimeAllowed + 1;
744 				}
745 				else if(difftime(time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD) {
746 					clientLagTime = (maxClientLagTimeAllowed * warnFrameCountLagPercent) + 1;
747 				}
748 				*/
749 				// END test
750 
751 
752 				//printf("skipNetworkBroadCast [%d] clientLagCount [%f][%f][%f] clientLagTime [%f][%f][%f]\n",skipNetworkBroadCast,clientLagCount,(maxFrameCountLagAllowed * warnFrameCountLagPercent),maxFrameCountLagAllowed,clientLagTime,(maxClientLagTimeAllowed * warnFrameCountLagPercent),maxClientLagTimeAllowed);
753 
754 				// New lag check
755 				if((maxFrameCountLagAllowed > 0 && clientLagCount > maxFrameCountLagAllowed) ||
756 					(maxClientLagTimeAllowed > 0 && clientLagTime > maxClientLagTimeAllowed) ||
757 					(maxFrameCountLagAllowedEver > 0 && clientLagCount > maxFrameCountLagAllowedEver) ||
758 					( maxClientLagTimeAllowedEver > 0 && clientLagTime > maxClientLagTimeAllowedEver)) {
759 
760 					clientLagExceededOrWarned.first = true;
761 					//printf("#1 Client Warned\n");
762 
763 			    	Lang &lang= Lang::getInstance();
764 			    	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
765 			    	for(unsigned int index = 0; index < languageList.size(); ++index) {
766 						char szBuf[4096]="";
767 
768 						string msgTemplate = "DROPPING %s, exceeded max allowed LAG count of %f [time = %f], clientLag = %f [%f], disconnecting client.";
769 						if(lang.hasString("ClientLagDropping") == true) {
770 							msgTemplate = lang.getString("ClientLagDropping",languageList[index]);
771 						}
772 						if(gameSettings.getNetworkPauseGameForLaggedClients() == true &&
773 							((maxFrameCountLagAllowedEver <= 0 || clientLagCount <= maxFrameCountLagAllowedEver) &&
774 							 (maxClientLagTimeAllowedEver <= 0 || clientLagTime <= maxClientLagTimeAllowedEver))) {
775 							msgTemplate = "PAUSING GAME TEMPORARILY for %s, exceeded max allowed LAG count of %f [time = %f], clientLag = %f [%f], waiting for client to catch up...";
776 							if(lang.hasString("ClientLagPausing") == true) {
777 								msgTemplate = lang.getString("ClientLagPausing",languageList[index]);
778 							}
779 						}
780 #ifdef WIN32
781 						_snprintf(szBuf,4095,msgTemplate.c_str(),connectionSlot->getName().c_str() ,maxFrameCountLagAllowed,maxClientLagTimeAllowed,clientLagCount,clientLagTime);
782 #else
783 						snprintf(szBuf,4095,msgTemplate.c_str(),connectionSlot->getName().c_str(),maxFrameCountLagAllowed,maxClientLagTimeAllowed,clientLagCount,clientLagTime);
784 #endif
785 						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,szBuf);
786 
787 						if(skipNetworkBroadCast == false) {
788 							string sMsg = szBuf;
789 							bool echoLocal = lang.isLanguageLocal(languageList[index]);
790 							sendTextMessage(sMsg,-1, echoLocal, languageList[index], connectionSlot->getPlayerIndex());
791 						}
792 			    	}
793 
794 					if(gameSettings.getNetworkPauseGameForLaggedClients() == false ||
795 						(maxFrameCountLagAllowedEver > 0 && clientLagCount > maxFrameCountLagAllowedEver) ||
796 						(maxClientLagTimeAllowedEver > 0 && clientLagTime > maxClientLagTimeAllowedEver)) {
797 
798 						//printf("Closing connection slot lagged out!\n");
799 						connectionSlot->close();
800 					}
801 
802 				}
803 				// New lag check warning
804 				else if((maxFrameCountLagAllowed > 0 && warnFrameCountLagPercent > 0 &&
805 						 clientLagCount > (maxFrameCountLagAllowed * warnFrameCountLagPercent)) ||
806 						(maxClientLagTimeAllowed > 0 && warnFrameCountLagPercent > 0 &&
807 						 clientLagTime > (maxClientLagTimeAllowed * warnFrameCountLagPercent)) ) {
808 
809 					clientLagExceededOrWarned.second = true;
810 					//printf("#2 Client Warned\n");
811 
812 					if(connectionSlot->getLagCountWarning() == false) {
813 						connectionSlot->setLagCountWarning(true);
814 
815 				    	Lang &lang= Lang::getInstance();
816 				    	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
817 				    	for(unsigned int index = 0; index < languageList.size(); ++index) {
818 				    		char szBuf[4096]="";
819 
820 				    		string msgTemplate = "LAG WARNING for %s, may exceed max allowed LAG count of %f [time = %f], clientLag = %f [%f], WARNING...";
821 							if(lang.hasString("ClientLagWarning") == true) {
822 								msgTemplate = lang.getString("ClientLagWarning",languageList[index]);
823 							}
824 
825 		#ifdef WIN32
826 				    		_snprintf(szBuf,4095,msgTemplate.c_str(),connectionSlot->getName().c_str(),maxFrameCountLagAllowed,maxClientLagTimeAllowed,clientLagCount,clientLagTime);
827 		#else
828 				    		snprintf(szBuf,4095,msgTemplate.c_str(),connectionSlot->getName().c_str(),maxFrameCountLagAllowed,maxClientLagTimeAllowed,clientLagCount,clientLagTime);
829 		#endif
830 				    		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,szBuf);
831 
832 							if(skipNetworkBroadCast == false) {
833 								string sMsg = szBuf;
834 								bool echoLocal = lang.isLanguageLocal(languageList[index]);
835 								sendTextMessage(sMsg,-1, echoLocal, languageList[index], connectionSlot->getPlayerIndex());
836 							}
837 				    	}
838 					}
839 				}
840 				else if(connectionSlot->getLagCountWarning() == true) {
841 					connectionSlot->setLagCountWarning(false);
842 				}
843 			}
844 		}
845 	}
846 	catch(const exception &ex) {
847 		alreadyInLagCheck = false;
848 
849 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
850 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ERROR [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
851 		throw megaglest_runtime_error(ex.what());
852 	}
853 
854 	alreadyInLagCheck = false;
855 	return clientLagExceededOrWarned;
856 }
857 
updateSocketTriggeredList(std::map<PLATFORM_SOCKET,bool> & socketTriggeredList)858 void ServerInterface::updateSocketTriggeredList(std::map<PLATFORM_SOCKET,bool> & socketTriggeredList) {
859 	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
860 		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
861 		ConnectionSlot *connectionSlot = slots[index];
862 		if(connectionSlot != NULL) {
863 			PLATFORM_SOCKET clientSocket = connectionSlot->getSocketId();
864 			if(Socket::isSocketValid(&clientSocket) == true) {
865 				socketTriggeredList[clientSocket] = false;
866 			}
867 		}
868 	}
869 }
870 
validateConnectedClients()871 void ServerInterface::validateConnectedClients() {
872 	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
873 		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
874 		ConnectionSlot* connectionSlot = slots[index];
875 		if(connectionSlot != NULL) {
876 			connectionSlot->validateConnection();
877 		}
878 	}
879 }
880 
signalClientReceiveCommands(ConnectionSlot * connectionSlot,int slotIndex,bool socketTriggered,ConnectionSlotEvent & event)881 bool ServerInterface::signalClientReceiveCommands(ConnectionSlot *connectionSlot,
882 		int slotIndex, bool socketTriggered, ConnectionSlotEvent & event) {
883 	bool slotSignalled 		= false;
884 
885 	event.eventType 		= eReceiveSocketData;
886 	event.networkMessage 	= NULL;
887 	event.connectionSlot 	= connectionSlot;
888 	event.socketTriggered 	= socketTriggered;
889 	event.triggerId 		= slotIndex;
890 	event.eventId 			= getNextEventId();
891 
892 	if(connectionSlot != NULL) {
893 		if(socketTriggered == true || connectionSlot->isConnected() == false) {
894 			connectionSlot->signalUpdate(&event);
895 			slotSignalled = true;
896 		}
897 	}
898 	return slotSignalled;
899 }
900 
signalClientsToRecieveData(std::map<PLATFORM_SOCKET,bool> & socketTriggeredList,std::map<int,ConnectionSlotEvent> & eventList,std::map<int,bool> & mapSlotSignalledList)901 void ServerInterface::signalClientsToRecieveData(std::map<PLATFORM_SOCKET,bool> &socketTriggeredList,
902 												 std::map<int,ConnectionSlotEvent> &eventList,
903 												 std::map<int,bool> & mapSlotSignalledList) {
904 	//printf("====================================In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
905 
906 	//printf("Signal clients get new data\n");
907 	const bool newThreadManager = Config::getInstance().getBool("EnableNewThreadManager","false");
908 	if(newThreadManager == true) {
909 		masterController.clearSlaves(true);
910 		std::vector<SlaveThreadControllerInterface *> slaveThreadList;
911 		for(int i= 0; exitServer == false && i < GameConstants::maxPlayers; ++i) {
912 			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[i],CODE_AT_LINE_X(i));
913 			ConnectionSlot* connectionSlot = slots[i];
914 
915 			bool socketTriggered = false;
916 
917 			if(connectionSlot != NULL) {
918 				PLATFORM_SOCKET clientSocket = connectionSlot->getSocketId();
919 				if(Socket::isSocketValid(&clientSocket)) {
920 					socketTriggered = socketTriggeredList[clientSocket];
921 				}
922 				else if(this->getGameHasBeenInitiated() == true &&
923 						this->getAllowInGameConnections() == true) {
924 					socketTriggeredList[clientSocket] = true;
925 					socketTriggered = socketTriggeredList[clientSocket];
926 				}
927 			}
928 			ConnectionSlotEvent &event = eventList[i];
929 			event.eventType 		= eReceiveSocketData;
930 			event.networkMessage 	= NULL;
931 			event.connectionSlot 	= connectionSlot;
932 			event.socketTriggered 	= socketTriggered;
933 			event.triggerId 		= i;
934 			event.eventId 			= getNextEventId();
935 
936 			if(connectionSlot != NULL) {
937 				if(socketTriggered == true || connectionSlot->isConnected() == false) {
938 					if(connectionSlot->getWorkerThread() != NULL) {
939 						slaveThreadList.push_back(connectionSlot->getWorkerThread());
940 						mapSlotSignalledList[i] = true;
941 					}
942 				}
943 			}
944 		}
945 		masterController.setSlaves(slaveThreadList);
946 		masterController.signalSlaves(&eventList);
947 	}
948 	else {
949 		for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
950 			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
951 			ConnectionSlot *connectionSlot = slots[index];
952 
953 			if(connectionSlot != NULL) {
954 				bool socketTriggered = false;
955 				PLATFORM_SOCKET clientSocket = connectionSlot->getSocketId();
956 				if(Socket::isSocketValid(&clientSocket)) {
957 					socketTriggered = socketTriggeredList[clientSocket];
958 				}
959 
960 				ConnectionSlotEvent &event = eventList[index];
961 				bool socketSignalled = signalClientReceiveCommands(connectionSlot,index,socketTriggered,event);
962 				if(connectionSlot != NULL && socketTriggered == true) {
963 					mapSlotSignalledList[index] = socketSignalled;
964 				}
965 			}
966 		}
967 	}
968 }
969 
checkForCompletedClientsUsingThreadManager(std::map<int,bool> & mapSlotSignalledList,std::vector<string> & errorMsgList)970 void ServerInterface::checkForCompletedClientsUsingThreadManager(
971 		std::map<int, bool> &mapSlotSignalledList, std::vector<string>& errorMsgList) {
972 
973 	masterController.waitTillSlavesTrigger(MAX_SLOT_THREAD_WAIT_TIME_MILLISECONDS);
974 	masterController.clearSlaves(true);
975 
976 	for (int i = 0; exitServer == false && i < GameConstants::maxPlayers; ++i) {
977 		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[i],CODE_AT_LINE_X(i));
978 
979 		ConnectionSlot* connectionSlot = slots[i];
980 		if (connectionSlot != NULL && mapSlotSignalledList[i] == true) {
981 
982 			try {
983 				std::vector<std::string> errorList =
984 						connectionSlot->getThreadErrorList();
985 				// Collect any collected errors from threads
986 				if (errorList.empty() == false) {
987 					for (int iErrIdx = 0; iErrIdx < (int) errorList.size();++iErrIdx) {
988 						string &sErr = errorList[iErrIdx];
989 
990 						if (sErr != "") {
991 							errorMsgList.push_back(sErr);
992 						}
993 					}
994 					connectionSlot->clearThreadErrorList();
995 				}
996 			} catch (const exception &ex) {
997 				SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
998 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
999 
1000 				errorMsgList.push_back(ex.what());
1001 			}
1002 		}
1003 	}
1004 }
1005 
checkForCompletedClientsUsingLoop(std::map<int,bool> & mapSlotSignalledList,std::vector<string> & errorMsgList,std::map<int,ConnectionSlotEvent> & eventList)1006 void ServerInterface::checkForCompletedClientsUsingLoop(
1007 		std::map<int, bool>& mapSlotSignalledList, std::vector<string> &errorMsgList,
1008 		std::map<int, ConnectionSlotEvent> &eventList) {
1009 
1010 	//time_t waitForThreadElapsed = time(NULL);
1011 	Chrono waitForThreadElapsed(true);
1012 
1013 	std::map<int, bool> slotsCompleted;
1014 	for (bool threadsDone = false; exitServer == false && threadsDone == false &&
1015 		 waitForThreadElapsed.getMillis() <= MAX_SLOT_THREAD_WAIT_TIME_MILLISECONDS;) {
1016 
1017 		threadsDone = true;
1018 		// Examine all threads for completion of delegation
1019 		for (int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
1020 			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
1021 
1022 			ConnectionSlot *connectionSlot = slots[index];
1023 			if (connectionSlot != NULL && connectionSlot->isConnected() == true &&
1024 				  mapSlotSignalledList[index] == true &&
1025 					connectionSlot->getJoinGameInProgress() == false &&
1026 				 	  slotsCompleted.find(index) == slotsCompleted.end()) {
1027 
1028 				try {
1029 					std::vector<std::string> errorList = connectionSlot->getThreadErrorList();
1030 					// Collect any collected errors from threads
1031 					if (errorList.empty() == false) {
1032 
1033 						for (int iErrIdx = 0; iErrIdx < (int) errorList.size();++iErrIdx) {
1034 
1035 							string &sErr = errorList[iErrIdx];
1036 							if (sErr != "") {
1037 								errorMsgList.push_back(sErr);
1038 							}
1039 						}
1040 						connectionSlot->clearThreadErrorList();
1041 					}
1042 
1043 					// Not done waiting for data yet
1044 					bool updateFinished = (connectionSlot != NULL ? connectionSlot->updateCompleted(&eventList[index]) : true);
1045 					if (updateFinished == false) {
1046 						threadsDone = false;
1047 						break;
1048 					}
1049 					else {
1050 						slotsCompleted[index] = true;
1051 					}
1052 				}
1053 				catch (const exception &ex) {
1054 					SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1055 					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1056 
1057 					errorMsgList.push_back(ex.what());
1058 				}
1059 			}
1060 		}
1061 	}
1062 }
1063 
getIpAddress(bool mutexLock)1064 std::string ServerInterface::getIpAddress(bool mutexLock) {
1065 	string result = serverSocket.getIpAddress();
1066 	return result;
1067 }
1068 
setClientLagCallbackInterface(ClientLagCallbackInterface * intf)1069 void ServerInterface::setClientLagCallbackInterface(ClientLagCallbackInterface *intf) {
1070 	this->clientLagCallbackInterface = intf;
1071 }
1072 
getClientsAutoPausedDueToLag()1073 bool ServerInterface::getClientsAutoPausedDueToLag() {
1074 	return this->clientsAutoPausedDueToLag;
1075 }
1076 
checkForCompletedClients(std::map<int,bool> & mapSlotSignalledList,std::vector<string> & errorMsgList,std::map<int,ConnectionSlotEvent> & eventList)1077 void ServerInterface::checkForCompletedClients(std::map<int,bool> & mapSlotSignalledList,
1078 											   std::vector <string> &errorMsgList,
1079 											   std::map<int,ConnectionSlotEvent> &eventList) {
1080 
1081 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1082 
1083 	const bool newThreadManager = Config::getInstance().getBool("EnableNewThreadManager","false");
1084 	if(newThreadManager == true) {
1085 		checkForCompletedClientsUsingThreadManager(mapSlotSignalledList, errorMsgList);
1086 	}
1087 	else {
1088 		checkForCompletedClientsUsingLoop(mapSlotSignalledList, errorMsgList, eventList);
1089 	}
1090 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1091 }
1092 
checkForAutoPauseForLaggingClient(int index,ConnectionSlot * connectionSlot)1093 void ServerInterface::checkForAutoPauseForLaggingClient(int index,ConnectionSlot* connectionSlot) {
1094 
1095 	if (gameSettings.getNetworkPauseGameForLaggedClients() == true &&
1096 			this->clientsAutoPausedDueToLag == false) {
1097 		if (connectionSlot != NULL && connectionSlot->isConnected() == true) {
1098 			if (connectionSlot->getAutoPauseGameCountForLag() < MAX_CLIENT_PAUSE_FOR_LAG_COUNT) {
1099 				if (this->clientLagCallbackInterface != NULL) {
1100 
1101 					if (this->clientsAutoPausedDueToLagTimer.isStarted() == false ||
1102 						this->clientsAutoPausedDueToLagTimer.getMillis() >= MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS) {
1103 
1104 						connectionSlot->incrementAutoPauseGameCountForLag();
1105 
1106 						this->clientsAutoPausedDueToLag = true;
1107 						if (this->clientLagCallbackInterface->clientLagHandler(index, true) == false) {
1108 							connectionSlot->close();
1109 						}
1110 						else {
1111 							if (this->clientsAutoPausedDueToLagTimer.isStarted()== true) {
1112 
1113 								this->clientsAutoPausedDueToLagTimer.reset();
1114 								this->clientsAutoPausedDueToLagTimer.stop();
1115 							}
1116 							this->clientsAutoPausedDueToLagTimer.start();
1117 						}
1118 					}
1119 				}
1120 			}
1121 		}
1122 	}
1123 }
1124 
checkForLaggingClients(std::map<int,bool> & mapSlotSignalledList,std::map<int,ConnectionSlotEvent> & eventList,std::map<PLATFORM_SOCKET,bool> & socketTriggeredList,std::vector<string> & errorMsgList)1125 void ServerInterface::checkForLaggingClients(std::map<int,bool> &mapSlotSignalledList,
1126 											std::map<int,ConnectionSlotEvent> &eventList,
1127 											std::map<PLATFORM_SOCKET,bool> &socketTriggeredList,
1128 											std::vector <string> &errorMsgList) {
1129 	bool lastGlobalLagCheckTimeUpdate = false;
1130 	if(gameHasBeenInitiated == true) {
1131 
1132 		//time_t waitForClientsElapsed = time(NULL);
1133 		Chrono waitForClientsElapsed(true);
1134 		//time_t waitForThreadElapsed = time(NULL);
1135 		Chrono waitForThreadElapsed(true);
1136 		std::map<int,bool> slotsCompleted;
1137 		std::map<int,bool> slotsWarnedList;
1138 
1139 		for(bool threadsDone = false;
1140 			exitServer == false && threadsDone == false &&
1141 			waitForThreadElapsed.getMillis() <= MAX_SLOT_THREAD_WAIT_TIME_MILLISECONDS;) {
1142 
1143 			threadsDone = true;
1144 			// Examine all threads for completion of delegation
1145 			for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
1146 				//printf("#1 Check lag for i: %d\n",i);
1147 
1148 				MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
1149 				ConnectionSlot* connectionSlot = slots[index];
1150 
1151 				if(connectionSlot != NULL && connectionSlot->isConnected() == true &&
1152 					connectionSlot->getSkipLagCheck() == false &&
1153 					mapSlotSignalledList[index] == true &&
1154 				    slotsCompleted.find(index) == slotsCompleted.end()) {
1155 
1156 					//printf("#2 Check lag for i: %d playerindex: %d name [%s] socket: %d\n",i,connectionSlot->getPlayerIndex(),connectionSlot->getName().c_str(),connectionSlot->getSocketId());
1157 					try {
1158 						std::vector<std::string> errorList = connectionSlot->getThreadErrorList();
1159 						// Show any collected errors from threads
1160 						if(errorList.empty() == false) {
1161 							for(int iErrIdx = 0; iErrIdx < (int)errorList.size(); ++iErrIdx) {
1162 								string &sErr = errorList[iErrIdx];
1163 								if(sErr != "") {
1164 									errorMsgList.push_back(sErr);
1165 								}
1166 							}
1167 							connectionSlot->clearThreadErrorList();
1168 						}
1169 
1170 						// Not done waiting for data yet
1171 						bool updateFinished = (connectionSlot != NULL ? connectionSlot->updateCompleted(&eventList[index]) : true);
1172 						if(updateFinished == false) {
1173 							//printf("#2a Check lag for i: %d\n",i);
1174 							threadsDone = false;
1175 							break;
1176 						}
1177 						else {
1178 							// New lag check
1179 							std::pair<bool,bool> clientLagExceededOrWarned = std::make_pair(false,false);
1180 							if( gameHasBeenInitiated == true && connectionSlot != NULL &&
1181 								connectionSlot->isConnected() == true) {
1182 								clientLagExceededOrWarned = clientLagCheck(connectionSlot,slotsWarnedList[index]);
1183 
1184 								if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, gameSettings.getNetworkPauseGameForLaggedClients() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second,gameSettings.getNetworkPauseGameForLaggedClients());
1185 
1186 								if(clientLagExceededOrWarned.first == true) {
1187 									slotsWarnedList[index] = true;
1188 								}
1189 							}
1190 							// If the client has exceeded lag and the server wants
1191 							// to pause while they catch up, re-trigger the
1192 							// client reader thread
1193 							if((clientLagExceededOrWarned.second == true &&
1194 								gameSettings.getNetworkPauseGameForLaggedClients() == true)) {
1195 
1196 								if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, waitForClientsElapsed.getMillis() = %d, MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second,(int)waitForClientsElapsed.getMillis(),MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS);
1197 
1198 								checkForAutoPauseForLaggingClient(index, connectionSlot);
1199 
1200 								slotsCompleted[index] = true;
1201 							}
1202 							else {
1203 								slotsCompleted[index] = true;
1204 							}
1205 						}
1206 					}
1207 					catch(const exception &ex) {
1208 						SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1209 						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1210 						errorMsgList.push_back(ex.what());
1211 					}
1212 				}
1213 
1214 				//printf("#3 Check lag for i: %d\n",i);
1215 				if(connectionSlot != NULL &&
1216 					connectionSlot->isConnected() == true &&
1217 					connectionSlot->getSkipLagCheck() == false) {
1218 					//printf("#4 Check lag for i: %d\n",i);
1219 
1220 					try {
1221 						if(gameHasBeenInitiated == true &&
1222 							difftime((long int)time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD &&
1223 							difftime((long int)time(NULL),lastGlobalLagCheckTime) >= LAG_CHECK_INTERVAL_PERIOD) {
1224 
1225 							//printf("\n\n\n^^^^^^^^^^^^^^ PART A\n\n\n");
1226 
1227 							// New lag check
1228 							std::pair<bool,bool> clientLagExceededOrWarned = std::make_pair(false,false);
1229 							if( connectionSlot != NULL && connectionSlot->isConnected() == true) {
1230 								//printf("\n\n\n^^^^^^^^^^^^^^ PART B\n\n\n");
1231 
1232 								lastGlobalLagCheckTimeUpdate = true;
1233 								clientLagExceededOrWarned = clientLagCheck(connectionSlot,slotsWarnedList[index]);
1234 
1235 								if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, gameSettings.getNetworkPauseGameForLaggedClients() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second,gameSettings.getNetworkPauseGameForLaggedClients());
1236 
1237 								if(clientLagExceededOrWarned.first == true) {
1238 									slotsWarnedList[index] = true;
1239 								}
1240 
1241 								// If the client has exceeded lag and the server wants
1242 								// to pause while they catch up, re-trigger the
1243 								// client reader thread
1244 								if((clientLagExceededOrWarned.second == true &&
1245 									gameSettings.getNetworkPauseGameForLaggedClients() == true)) {
1246 
1247 									if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, waitForClientsElapsed.getMillis() = %d, MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second,(int)waitForClientsElapsed.getMillis(),MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS);
1248 
1249 									checkForAutoPauseForLaggingClient(index, connectionSlot);
1250 								}
1251 							}
1252 						}
1253 					}
1254 					catch(const exception &ex) {
1255 						SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1256 						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1257 						errorMsgList.push_back(ex.what());
1258 					}
1259 				}
1260 
1261 				//printf("#5 Check lag for i: %d\n",i);
1262 			}
1263 		}
1264 	}
1265 	if(lastGlobalLagCheckTimeUpdate == true) {
1266 		lastGlobalLagCheckTime = time(NULL);
1267 	}
1268 }
1269 
executeNetworkCommandsFromClients()1270 void ServerInterface::executeNetworkCommandsFromClients() {
1271 	if(gameHasBeenInitiated == true) {
1272 		for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
1273 			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
1274 			ConnectionSlot* connectionSlot= slots[index];
1275 			if(connectionSlot != NULL && connectionSlot->isConnected() == true) {
1276 				vector<NetworkCommand> pendingList = connectionSlot->getPendingNetworkCommandList(true);
1277 				if(pendingList.empty() == false) {
1278 					for(int idx = 0; exitServer == false && idx < (int)pendingList.size(); ++idx) {
1279 						NetworkCommand &cmd = pendingList[idx];
1280 						this->requestCommand(&cmd);
1281 					}
1282 					//printf("Executed: %d commands from slot: %d\n",pendingList.size(),index);
1283 				}
1284 			}
1285 		}
1286 	}
1287 }
1288 
dispatchPendingChatMessages(std::vector<string> & errorMsgList)1289 void ServerInterface::dispatchPendingChatMessages(std::vector <string> &errorMsgList) {
1290 	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
1291 
1292 		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
1293 		ConnectionSlot *connectionSlot = slots[index];
1294 
1295 		if(connectionSlot != NULL &&
1296 		   connectionSlot->getChatTextList(false).empty() == false) {
1297 			try {
1298 				std::vector<ChatMsgInfo> chatText = connectionSlot->getChatTextList(true);
1299 				for(int chatIdx = 0;
1300 					exitServer == false && slots[index] != NULL &&
1301 					chatIdx < (int)chatText.size(); chatIdx++) {
1302 
1303 					connectionSlot = slots[index];
1304 					if(connectionSlot != NULL) {
1305 						ChatMsgInfo msg(chatText[chatIdx]);
1306 						this->addChatInfo(msg);
1307 
1308 						string newChatText     = msg.chatText.c_str();
1309 						int newChatTeamIndex   = msg.chatTeamIndex;
1310 						int newChatPlayerIndex = msg.chatPlayerIndex;
1311 						string newChatLanguage = msg.targetLanguage;
1312 
1313 						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #1 about to broadcast nmtText chatText [%s] chatTeamIndex = %d, newChatPlayerIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex,newChatPlayerIndex);
1314 
1315 						if(newChatLanguage == "" ||
1316 							newChatLanguage == connectionSlot->getNetworkPlayerLanguage()) {
1317 
1318 							NetworkMessageText networkMessageText(newChatText.c_str(),newChatTeamIndex,newChatPlayerIndex,newChatLanguage);
1319 							broadcastMessage(&networkMessageText, connectionSlot->getPlayerIndex(),index);
1320 						}
1321 
1322 						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtText chatText [%s] chatTeamIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex);
1323 					}
1324 				}
1325 
1326 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] index = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,index);
1327 				// Its possible that the slot is disconnected here
1328 				// so check the original pointer again
1329 				if(slots[index] != NULL) {
1330 					slots[index]->clearChatInfo();
1331 				}
1332 			}
1333 			catch(const exception &ex) {
1334 				SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1335 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1336 				errorMsgList.push_back(ex.what());
1337 			}
1338 		}
1339 	}
1340 }
1341 
dispatchPendingMarkCellMessages(std::vector<string> & errorMsgList)1342 void ServerInterface::dispatchPendingMarkCellMessages(std::vector <string> &errorMsgList) {
1343 	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
1344 
1345 		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
1346 		ConnectionSlot* connectionSlot= slots[index];
1347 
1348 		if(connectionSlot != NULL &&
1349 		   connectionSlot->getMarkedCellList(false).empty() == false) {
1350 
1351 			try {
1352 				std::vector<MarkedCell> chatText = connectionSlot->getMarkedCellList(true);
1353 				for(int chatIdx = 0;
1354 					exitServer == false && slots[index] != NULL &&
1355 					chatIdx < (int)chatText.size(); chatIdx++) {
1356 
1357 					connectionSlot= slots[index];
1358 					if(connectionSlot != NULL) {
1359 						MarkedCell msg(chatText[chatIdx]);
1360 						this->addMarkedCell(msg);
1361 
1362 						NetworkMessageMarkCell networkMessageMarkCell(msg.getTargetPos(),msg.getFactionIndex(),msg.getNote(),msg.getPlayerIndex());
1363 						broadcastMessage(&networkMessageMarkCell, connectionSlot->getPlayerIndex(),index);
1364 						//if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtText chatText [%s] chatTeamIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex);
1365 					}
1366 				}
1367 
1368 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] i = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,index);
1369 				// Its possible that the slot is disconnected here
1370 				// so check the original pointer again
1371 				if(slots[index] != NULL) {
1372 					slots[index]->clearMarkedCellList();
1373 				}
1374 			}
1375 			catch(const exception &ex) {
1376 				SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1377 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1378 				errorMsgList.push_back(ex.what());
1379 			}
1380 		}
1381 	}
1382 }
dispatchPendingHighlightCellMessages(std::vector<string> & errorMsgList)1383 void ServerInterface::dispatchPendingHighlightCellMessages(std::vector <string> &errorMsgList) {
1384 	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
1385 
1386 		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
1387 		ConnectionSlot* connectionSlot= slots[index];
1388 		if(connectionSlot != NULL &&
1389 		   connectionSlot->getHighlightedCellList(false).empty() == false) {
1390 
1391 			try {
1392 				std::vector<MarkedCell> highlightedCells = connectionSlot->getHighlightedCellList(true);
1393 				for(int chatIdx = 0;
1394 					exitServer == false && slots[index] != NULL &&
1395 					chatIdx < (int)highlightedCells.size(); chatIdx++) {
1396 
1397 					connectionSlot= slots[index];
1398 					if(connectionSlot != NULL) {
1399 						MarkedCell msg(highlightedCells[chatIdx]);
1400 						this->setHighlightedCell(msg);
1401 
1402 						NetworkMessageHighlightCell networkMessageHighlightCell(msg.getTargetPos(),msg.getFactionIndex());
1403 						broadcastMessage(&networkMessageHighlightCell, connectionSlot->getPlayerIndex(),index);
1404 					}
1405 				}
1406 
1407 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] index = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,index);
1408 				// Its possible that the slot is disconnected here
1409 				// so check the original pointer again
1410 				if(slots[index] != NULL) {
1411 					slots[index]->clearHighlightedCellList();
1412 				}
1413 			}
1414 			catch(const exception &ex) {
1415 				SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1416 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1417 				errorMsgList.push_back(ex.what());
1418 			}
1419 		}
1420 	}
1421 }
1422 
dispatchPendingUnMarkCellMessages(std::vector<string> & errorMsgList)1423 void ServerInterface::dispatchPendingUnMarkCellMessages(std::vector <string> &errorMsgList) {
1424 	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
1425 
1426 		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
1427 		ConnectionSlot* connectionSlot= slots[index];
1428 		if(connectionSlot != NULL &&
1429 		   connectionSlot->getUnMarkedCellList(false).empty() == false) {
1430 
1431 			try {
1432 				std::vector<UnMarkedCell> chatText = connectionSlot->getUnMarkedCellList(true);
1433 				for(int chatIdx = 0;
1434 					exitServer == false && slots[index] != NULL &&
1435 					chatIdx < (int)chatText.size(); chatIdx++) {
1436 
1437 					connectionSlot = slots[index];
1438 					if(connectionSlot != NULL) {
1439 						UnMarkedCell msg(chatText[chatIdx]);
1440 						this->addUnMarkedCell(msg);
1441 
1442 						NetworkMessageUnMarkCell networkMessageMarkCell(msg.getTargetPos(),msg.getFactionIndex());
1443 						broadcastMessage(&networkMessageMarkCell, connectionSlot->getPlayerIndex(),index);
1444 						//if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtText chatText [%s] chatTeamIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex);
1445 					}
1446 				}
1447 
1448 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] i = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,index);
1449 				// Its possible that the slot is disconnected here
1450 				// so check the original pointer again
1451 				if(slots[index] != NULL) {
1452 					slots[index]->clearUnMarkedCellList();
1453 				}
1454 			}
1455 			catch(const exception &ex) {
1456 				SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1457 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1458 				errorMsgList.push_back(ex.what());
1459 			}
1460 		}
1461 	}
1462 }
1463 
checkForAutoResumeForLaggingClients()1464 void ServerInterface::checkForAutoResumeForLaggingClients() {
1465 	if (gameSettings.getNetworkPauseGameForLaggedClients() == true &&
1466 		this->clientsAutoPausedDueToLag == true &&
1467 		this->clientsAutoPausedDueToLagTimer.getMillis() >= MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE_MILLISECONDS) {
1468 
1469 		//printf("this->clientsAutoPausedDueToLag: %d [%lld]\n",this->clientsAutoPausedDueToLag,(long long)this->clientsAutoPausedDueToLagTimer.getMillis());
1470 		if (this->clientLagCallbackInterface != NULL) {
1471 
1472 			this->clientsAutoPausedDueToLag = false;
1473 			this->clientLagCallbackInterface->clientLagHandler(-1, false);
1474 
1475 			this->clientsAutoPausedDueToLagTimer.reset();
1476 			this->clientsAutoPausedDueToLagTimer.stop();
1477 			this->clientsAutoPausedDueToLagTimer.start();
1478 		}
1479 	}
1480 }
1481 
update()1482 void ServerInterface::update() {
1483 	//printf("\nServerInterface::update -- A\n");
1484 
1485 	std::vector <string> errorMsgList;
1486 	try {
1487 		// The first thing we will do is check all clients to ensure they have
1488 		// properly identified themselves within the alloted time period
1489 		validateConnectedClients();
1490 
1491 		//printf("\nServerInterface::update -- B\n");
1492 
1493 		processTextMessageQueue();
1494 		processBroadCastMessageQueue();
1495 
1496 		checkForAutoResumeForLaggingClients();
1497 
1498 		//printf("\nServerInterface::update -- C\n");
1499 
1500 		std::map<PLATFORM_SOCKET,bool> socketTriggeredList;
1501 		//update all slots
1502 		updateSocketTriggeredList(socketTriggeredList);
1503 
1504 		//printf("\nServerInterface::update -- D\n");
1505 
1506 		if(gameHasBeenInitiated == false ||
1507 			socketTriggeredList.empty() == false) {
1508 			//printf("\nServerInterface::update -- E\n");
1509 
1510 			std::map<int,ConnectionSlotEvent> eventList;
1511 
1512 			bool hasData = false;
1513 			if(gameHasBeenInitiated == false) {
1514 				hasData = Socket::hasDataToRead(socketTriggeredList);
1515 			}
1516 			else {
1517 				hasData = true;
1518 			}
1519 
1520 			if(hasData && SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] hasData == true\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);
1521 
1522 			if(gameHasBeenInitiated == false || hasData == true) {
1523 				//printf("START Server update #2\n");
1524 				std::map<int,bool> mapSlotSignalledList;
1525 
1526 				// Step #1 tell all connection slot worker threads to receive socket data
1527 				if(gameHasBeenInitiated == false) {
1528 					signalClientsToRecieveData(socketTriggeredList, eventList, mapSlotSignalledList);
1529 				}
1530 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #2\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1531 
1532 				//printf("START Server update #2\n");
1533 				if(gameHasBeenInitiated == false || hasData == true) {
1534 					//printf("START Server update #3\n");
1535 
1536 					// Step #2 check all connection slot worker threads for completed status
1537 					if(gameHasBeenInitiated == false) {
1538 						checkForCompletedClients(mapSlotSignalledList,errorMsgList, eventList);
1539 					}
1540 					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #3\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1541 
1542 					//printf("START Server update #4\n");
1543 					//printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1544 
1545 					// Step #3 check clients for any lagging scenarios and try to deal with them
1546 					if(gameHasBeenInitiated == false) {
1547 						checkForLaggingClients(mapSlotSignalledList, eventList, socketTriggeredList,errorMsgList);
1548 					}
1549 					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #4\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1550 
1551 					//printf("START Server update #5\n");
1552 					//printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1553 					// Step #4 dispatch network commands to the pending list so that they are done in proper order
1554 					executeNetworkCommandsFromClients();
1555 					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #5\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1556 
1557 					//printf("START Server update #6\n");
1558 					//printf("In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1559 					// Step #5 dispatch pending chat messages
1560 					dispatchPendingChatMessages(errorMsgList);
1561 					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
1562 
1563 					dispatchPendingMarkCellMessages(errorMsgList);
1564 					dispatchPendingUnMarkCellMessages(errorMsgList);
1565 
1566 					dispatchPendingHighlightCellMessages(errorMsgList);
1567 
1568 					if(gameHasBeenInitiated == true &&
1569 						difftime((long int)time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD &&
1570 						difftime((long int)time(NULL),lastGlobalLagCheckTime) >= LAG_CHECK_INTERVAL_PERIOD) {
1571 
1572 						std::map<int,bool> mapSlotSignalledList;
1573 						checkForLaggingClients(mapSlotSignalledList, eventList, socketTriggeredList,errorMsgList);
1574 					}
1575 					//printf("START Server update #7\n");
1576 				}
1577 				else if(gameHasBeenInitiated == true &&
1578 						difftime((long int)time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD &&
1579 						difftime((long int)time(NULL),lastGlobalLagCheckTime) >= LAG_CHECK_INTERVAL_PERIOD) {
1580 
1581 					//printf("Skip network data process because hasData == false\n");
1582 					//printf("START Server update #8\n");
1583 
1584 					std::map<int,bool> mapSlotSignalledList;
1585 					checkForLaggingClients(mapSlotSignalledList, eventList, socketTriggeredList,errorMsgList);
1586 				}
1587 				//printf("START Server update #9\n");
1588 			}
1589 			else if(gameHasBeenInitiated == true &&
1590 					difftime((long int)time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD &&
1591 					difftime((long int)time(NULL),lastGlobalLagCheckTime) >= LAG_CHECK_INTERVAL_PERIOD) {
1592 
1593 				//printf("\nServerInterface::update -- E1\n");
1594 				//printf("START Server update #10\n");
1595 
1596 				std::map<int,bool> mapSlotSignalledList;
1597 				checkForLaggingClients(mapSlotSignalledList, eventList, socketTriggeredList,errorMsgList);
1598 			}
1599 			//printf("START Server update #11\n");
1600 		}
1601 		else if(gameHasBeenInitiated == true &&
1602 				difftime((long int)time(NULL),gameStartTime) >= LAG_CHECK_GRACE_PERIOD &&
1603 				difftime((long int)time(NULL),lastGlobalLagCheckTime) >= LAG_CHECK_INTERVAL_PERIOD) {
1604 
1605 			//printf("\nServerInterface::update -- F\n");
1606 			//printf("START Server update #12\n");
1607 
1608 			std::map<int,ConnectionSlotEvent> eventList;
1609 			std::map<int,bool> mapSlotSignalledList;
1610 
1611 			checkForLaggingClients(mapSlotSignalledList, eventList, socketTriggeredList,errorMsgList);
1612 		}
1613 		//printf("START Server update #13\n");
1614 
1615 		// Check if we need to switch masterserver admin to a new player because original admin disconnected
1616 		if(gameHasBeenInitiated == true &&
1617 			this->gameSettings.getMasterserver_admin() > 0) {
1618 
1619 			bool foundAdminSlot 	= false;
1620 			int iFirstConnectedSlot = -1;
1621 			for(int index = 0; index < GameConstants::maxPlayers; ++index) {
1622 				MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
1623 				if(slots[index] != NULL && slots[index]->isConnected() == true) {
1624 					if(iFirstConnectedSlot < 0) {
1625 						iFirstConnectedSlot = index;
1626 					}
1627 					if(this->gameSettings.getMasterserver_admin() == slots[index]->getSessionKey()) {
1628 						foundAdminSlot = true;
1629 						break;
1630 					}
1631 				}
1632 			}
1633 
1634 			if(foundAdminSlot == false && iFirstConnectedSlot >= 0) {
1635 				printf("Switching masterserver admin to slot#%d...\n",iFirstConnectedSlot);
1636 
1637 				MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[iFirstConnectedSlot],CODE_AT_LINE_X(iFirstConnectedSlot));
1638 				if(slots[iFirstConnectedSlot] != NULL) {
1639 					string sMsg = "Switching player to admin mode: " + slots[iFirstConnectedSlot]->getName();
1640 					sendTextMessage(sMsg,-1, true,"");
1641 
1642 					this->gameSettings.setMasterserver_admin(slots[iFirstConnectedSlot]->getSessionKey());
1643 					this->gameSettings.setMasterserver_admin_faction_index(slots[iFirstConnectedSlot]->getPlayerIndex());
1644 
1645 					safeMutexSlot.ReleaseLock();
1646 					this->broadcastGameSetup(&this->gameSettings);
1647 				}
1648 			}
1649 		}
1650 		//printf("\nServerInterface::update -- G\n");
1651 		//printf("START Server update #14\n");
1652 
1653 		checkListenerSlots();
1654 
1655 		//printf("START Server update #15\n");
1656 	}
1657 	catch(const exception &ex) {
1658 		//printf("\nServerInterface::update -- H\n");
1659 
1660 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1661 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1662 		errorMsgList.push_back(ex.what());
1663 	}
1664 
1665 	if(errorMsgList.empty() == false){
1666 		for(int iErrIdx = 0; iErrIdx < (int)errorMsgList.size(); ++iErrIdx) {
1667 			string &sErr = errorMsgList[iErrIdx];
1668 			if(sErr != "") {
1669 				DisplayErrorMessage(sErr);
1670 			}
1671 		}
1672 	}
1673 }
1674 
updateKeyframe(int frameCount)1675 void ServerInterface::updateKeyframe(int frameCount) {
1676 	currentFrameCount = frameCount;
1677 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] currentFrameCount = %d, requestedCommands.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,currentFrameCount,requestedCommands.size());
1678 
1679 	NetworkMessageCommandList networkMessageCommandList(frameCount);
1680 	for(int index = 0; index < GameConstants::maxPlayers; ++index) {
1681 		networkMessageCommandList.setNetworkPlayerFactionCRC(index,this->getNetworkPlayerFactionCRC(index));
1682 	}
1683 
1684 	while(requestedCommands.empty() == false) {
1685 		// First add the command to the broadcast list (for all clients)
1686 		if(networkMessageCommandList.addCommand(&requestedCommands.back())) {
1687 			// Add the command to the local server command list
1688 			pendingCommands.push_back(requestedCommands.back());
1689 			requestedCommands.pop_back();
1690 		}
1691 		else {
1692 			break;
1693 		}
1694 	}
1695 
1696 	try {
1697 		// Possible cause of out of synch since we have more commands that need
1698 		// to be sent in this frame
1699 		if(requestedCommands.empty() == false) {
1700 			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] WARNING / ERROR, requestedCommands.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,requestedCommands.size());
1701 			SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] WARNING / ERROR, requestedCommands.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,requestedCommands.size());
1702 
1703 			string sMsg = "may go out of synch: server requestedCommands.size() = " + intToStr(requestedCommands.size());
1704 			sendTextMessage(sMsg,-1, true,"");
1705 		}
1706 
1707 		// broadcast commands
1708 		// If we have more than 0 commands to send, automatically broadcast them
1709 		bool sendBroadcastMessage = (networkMessageCommandList.getCommandCount() > 0);
1710 		if(sendBroadcastMessage == false) {
1711 
1712 			// Is auto pause due to lag NOT enabled
1713 			if(this->getClientsAutoPausedDueToLag() == false) {
1714 
1715 				// ****NOTE:
1716 				// We always need to broadcast when not pause as clients
1717 				// look for broadcasts every network frame.
1718 				sendBroadcastMessage = true;
1719 			}
1720 			// Auto pause is enabled due to client lagging, only send empty command
1721 			// broadcasts every MAX_EMPTY_NETWORK_COMMAND_LIST_BROADCAST_INTERVAL_MILLISECONDS
1722 			else if(this->getClientsAutoPausedDueToLag() == true &&
1723 					(lastBroadcastCommandsTimer.isStarted() == false ||
1724 					 lastBroadcastCommandsTimer.getMillis() >= MAX_EMPTY_NETWORK_COMMAND_LIST_BROADCAST_INTERVAL_MILLISECONDS)) {
1725 
1726 				sendBroadcastMessage = true;
1727 			}
1728 		}
1729 
1730 		if(sendBroadcastMessage == true) {
1731 
1732 			if(lastBroadcastCommandsTimer.isStarted() == false) {
1733 				lastBroadcastCommandsTimer.start();
1734 			}
1735 			else {
1736 				lastBroadcastCommandsTimer.stop();
1737 				lastBroadcastCommandsTimer.reset();
1738 				lastBroadcastCommandsTimer.start();
1739 			}
1740 			broadcastMessage(&networkMessageCommandList);
1741 		}
1742 	}
1743 	catch(const exception &ex) {
1744 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1745 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
1746 		DisplayErrorMessage(ex.what());
1747 	}
1748 }
1749 
shouldDiscardNetworkMessage(NetworkMessageType networkMessageType,ConnectionSlot * connectionSlot)1750 bool ServerInterface::shouldDiscardNetworkMessage(NetworkMessageType networkMessageType,
1751 												ConnectionSlot *connectionSlot) {
1752 	bool discard = false;
1753 	if(connectionSlot != NULL) {
1754 		switch(networkMessageType) {
1755 			case nmtIntro:
1756 				{
1757 				discard = true;
1758 				NetworkMessageIntro msg = NetworkMessageIntro();
1759 				connectionSlot->receiveMessage(&msg);
1760 				}
1761 				break;
1762 			case nmtPing:
1763 				{
1764 				discard = true;
1765 				NetworkMessagePing msg = NetworkMessagePing();
1766 				connectionSlot->receiveMessage(&msg);
1767 				lastPingInfo = msg;
1768 				}
1769 				break;
1770 
1771 			case nmtLaunch:
1772 				{
1773 				discard = true;
1774 				NetworkMessageLaunch msg = NetworkMessageLaunch();
1775 				connectionSlot->receiveMessage(&msg);
1776 				}
1777 				break;
1778 			case nmtText:
1779 				{
1780 				discard = true;
1781 				NetworkMessageText netMsg = NetworkMessageText();
1782 				connectionSlot->receiveMessage(&netMsg);
1783 
1784 				ChatMsgInfo msg(netMsg.getText().c_str(),netMsg.getTeamIndex(),netMsg.getPlayerIndex(),netMsg.getTargetLanguage());
1785 				this->addChatInfo(msg);
1786 
1787 				string newChatText     = msg.chatText.c_str();
1788 				//string newChatSender   = msg.chatSender.c_str();
1789 				int newChatTeamIndex   = msg.chatTeamIndex;
1790 				int newChatPlayerIndex = msg.chatPlayerIndex;
1791 				string newChatLanguage = msg.targetLanguage.c_str();
1792 
1793 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #1 about to broadcast nmtText chatText [%s] chatTeamIndex = %d, newChatPlayerIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex,newChatPlayerIndex);
1794 
1795 				NetworkMessageText networkMessageText(newChatText.c_str(),newChatTeamIndex,newChatPlayerIndex,newChatLanguage);
1796 				broadcastMessage(&networkMessageText, connectionSlot->getPlayerIndex());
1797 
1798 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtText chatText [%s] chatTeamIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex);
1799 
1800 				}
1801 				break;
1802 
1803 			case nmtMarkCell:
1804 				{
1805 				discard = true;
1806 				NetworkMessageMarkCell networkMessageMarkCell;
1807 				connectionSlot->receiveMessage(&networkMessageMarkCell);
1808 
1809             	MarkedCell msg(networkMessageMarkCell.getTarget(),
1810             			       networkMessageMarkCell.getFactionIndex(),
1811             			       networkMessageMarkCell.getText().c_str(),
1812             			       networkMessageMarkCell.getPlayerIndex());
1813 
1814             	this->addMarkedCell(msg);
1815 
1816             	NetworkMessageMarkCell networkMessageMarkCellBroadcast(
1817             			networkMessageMarkCell.getTarget(),
1818      			        networkMessageMarkCell.getFactionIndex(),
1819      			        networkMessageMarkCell.getText().c_str(),
1820      			        networkMessageMarkCell.getPlayerIndex());
1821 				broadcastMessage(&networkMessageMarkCellBroadcast, connectionSlot->getPlayerIndex());
1822 
1823 				//if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtMarkCell chatText [%s] chatTeamIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex);
1824 
1825 				}
1826 				break;
1827 
1828 			case nmtUnMarkCell:
1829 				{
1830 				discard = true;
1831 				NetworkMessageUnMarkCell networkMessageMarkCell;
1832 				connectionSlot->receiveMessage(&networkMessageMarkCell);
1833 
1834             	UnMarkedCell msg(networkMessageMarkCell.getTarget(),
1835             			       networkMessageMarkCell.getFactionIndex());
1836 
1837             	this->addUnMarkedCell(msg);
1838 
1839             	NetworkMessageUnMarkCell networkMessageMarkCellBroadcast(
1840             			networkMessageMarkCell.getTarget(),
1841      			        networkMessageMarkCell.getFactionIndex());
1842 				broadcastMessage(&networkMessageMarkCellBroadcast, connectionSlot->getPlayerIndex());
1843 
1844 				//if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtMarkCell chatText [%s] chatTeamIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatText.c_str(),newChatTeamIndex);
1845 
1846 				}
1847 				break;
1848 			case nmtHighlightCell:
1849 				{
1850 				discard = true;
1851 				NetworkMessageHighlightCell networkMessageHighlightCell;
1852 				connectionSlot->receiveMessage(&networkMessageHighlightCell);
1853 
1854             	MarkedCell msg(networkMessageHighlightCell.getTarget(),
1855             			networkMessageHighlightCell.getFactionIndex(),
1856             			"none",-1);
1857 
1858             	this->setHighlightedCell(msg);
1859 
1860             	NetworkMessageHighlightCell networkMessageHighlightCellBroadcast(
1861             			networkMessageHighlightCell.getTarget(),
1862             			networkMessageHighlightCell.getFactionIndex());
1863 				broadcastMessage(&networkMessageHighlightCellBroadcast, connectionSlot->getPlayerIndex());
1864 
1865 				//if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtMarkCell  chatTeamIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,newChatTeamIndex);
1866 
1867 				}
1868 				break;
1869 
1870 			case nmtSynchNetworkGameData:
1871 				{
1872 				discard = true;
1873 				NetworkMessageSynchNetworkGameData msg = NetworkMessageSynchNetworkGameData();
1874 				connectionSlot->receiveMessage(&msg);
1875 				}
1876 				break;
1877 			case nmtSynchNetworkGameDataStatus:
1878 				{
1879 				discard = true;
1880 				NetworkMessageSynchNetworkGameDataStatus msg = NetworkMessageSynchNetworkGameDataStatus();
1881 				connectionSlot->receiveMessage(&msg);
1882 				}
1883 				break;
1884 			case nmtSynchNetworkGameDataFileCRCCheck:
1885 				{
1886 				discard = true;
1887 				NetworkMessageSynchNetworkGameDataFileCRCCheck msg = NetworkMessageSynchNetworkGameDataFileCRCCheck();
1888 				connectionSlot->receiveMessage(&msg);
1889 				}
1890 				break;
1891 			case nmtSynchNetworkGameDataFileGet:
1892 				{
1893 				discard = true;
1894 				NetworkMessageSynchNetworkGameDataFileGet msg = NetworkMessageSynchNetworkGameDataFileGet();
1895 				connectionSlot->receiveMessage(&msg);
1896 				}
1897 				break;
1898 			case nmtSwitchSetupRequest:
1899 				{
1900 				discard = true;
1901 				SwitchSetupRequest msg = SwitchSetupRequest();
1902 				connectionSlot->receiveMessage(&msg);
1903 				}
1904 				break;
1905 			case nmtPlayerIndexMessage:
1906 				{
1907 				discard = true;
1908 				PlayerIndexMessage msg = PlayerIndexMessage(0);
1909 				connectionSlot->receiveMessage(&msg);
1910 				}
1911 				break;
1912 		}
1913 	}
1914 	return discard;
1915 }
1916 
waitUntilReady(Checksum * checksum)1917 void ServerInterface::waitUntilReady(Checksum *checksum) {
1918 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s] START\n",__FUNCTION__);
1919 	Logger & logger = Logger::getInstance();
1920 	gameHasBeenInitiated = true;
1921 	Chrono chrono;
1922 	chrono.start();
1923 
1924 	bool allReady = false;
1925 
1926 	if(Config::getInstance().getBool("EnableGameServerLoadCancel","false") == true) {
1927 		logger.setCancelLoadingEnabled(true);
1928 	}
1929 
1930 	Lang &lang							= Lang::getInstance();
1931 	uint64 waitLoopIterationCount 		= 0;
1932 	uint64 MAX_LOOP_COUNT_BEFORE_SLEEP 	= 10;
1933 	MAX_LOOP_COUNT_BEFORE_SLEEP 		= Config::getInstance().getInt("NetworkServerLoopGameLoadingCap",intToStr(MAX_LOOP_COUNT_BEFORE_SLEEP).c_str());
1934 	if(MAX_LOOP_COUNT_BEFORE_SLEEP == 0) {
1935 		MAX_LOOP_COUNT_BEFORE_SLEEP = 1;
1936 	}
1937 	int sleepMillis 		= Config::getInstance().getInt("NetworkServerLoopGameLoadingCapSleepMillis","10");
1938 	int64 lastStatusUpdate 	= 0;
1939 
1940 	while(exitServer == false &&
1941 			allReady == false &&
1942 			logger.getCancelLoading() == false) {
1943 
1944 		waitLoopIterationCount++;
1945 		if(waitLoopIterationCount > 0 &&
1946 			waitLoopIterationCount % MAX_LOOP_COUNT_BEFORE_SLEEP == 0) {
1947 
1948 			sleep(sleepMillis);
1949 			waitLoopIterationCount = 0;
1950 		}
1951 		vector<string> waitingForHosts;
1952 		allReady= true;
1953 		for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index)	{
1954 
1955 			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
1956 			ConnectionSlot* connectionSlot= slots[index];
1957 			if(connectionSlot != NULL && connectionSlot->isConnected() == true)	{
1958 				if(connectionSlot->isReady() == false) {
1959 
1960 					NetworkMessageType networkMessageType= connectionSlot->getNextMessageType();
1961 
1962 					// consume old messages from the lobby
1963 					bool discarded = shouldDiscardNetworkMessage(networkMessageType,connectionSlot);
1964 					if(discarded == false) {
1965 
1966 						NetworkMessageReady networkMessageReady;
1967 						if(networkMessageType == nmtReady &&
1968 						   connectionSlot->receiveMessage(&networkMessageReady)) {
1969 
1970 							if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s] networkMessageType==nmtReady\n",__FUNCTION__);
1971 
1972 							connectionSlot->setReady();
1973 							connectionSlot->setGameStarted(true);
1974 						}
1975 						else if(networkMessageType != nmtInvalid) {
1976 							string sErr = "Unexpected network message: " + intToStr(networkMessageType);
1977 							sendTextMessage(sErr,-1, true,"",index);
1978 							DisplayErrorMessage(sErr);
1979 							logger.setCancelLoading(false);
1980 							return;
1981 						}
1982 					}
1983 					waitingForHosts.push_back(connectionSlot->getName());
1984 					allReady= false;
1985 				}
1986 			}
1987 		}
1988 
1989 		//check for timeout
1990 		if(allReady == false) {
1991 			if(chrono.getMillis() > readyWaitTimeout) {
1992 		    	Lang &lang= Lang::getInstance();
1993 		    	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
1994 		    	for(unsigned int langIndex = 0; langIndex < languageList.size(); ++langIndex) {
1995 					string sErr = "Timeout waiting for clients.";
1996 					if(lang.hasString("TimeoutWaitingForClients") == true) {
1997 						sErr = lang.getString("TimeoutWaitingForClients",languageList[langIndex]);
1998 					}
1999 					bool localEcho = lang.isLanguageLocal(languageList[langIndex]);
2000 					sendTextMessage(sErr,-1, localEcho, languageList[langIndex]);
2001 					if(localEcho == true) {
2002 						DisplayErrorMessage(sErr);
2003 					}
2004 		    	}
2005 				logger.setCancelLoading(false);
2006 				return;
2007 			}
2008 			else {
2009 				if(chrono.getMillis() - lastStatusUpdate > 200) {
2010 					lastStatusUpdate = chrono.getMillis();
2011 
2012 					string waitForHosts = "";
2013 					for(int hostIndex = 0; hostIndex < (int)waitingForHosts.size(); hostIndex++) {
2014 						if(waitForHosts != "") {
2015 							waitForHosts += ", ";
2016 						}
2017 						waitForHosts += waitingForHosts[hostIndex];
2018 					}
2019 
2020 					char szBuf[8096]="";
2021 					string updateTextFormat = lang.getString("NetworkGameServerLoadStatus");
2022 					if(updateTextFormat == "" ||
2023 						updateTextFormat[0] == '?') {
2024 
2025 						updateTextFormat =  "Waiting for network: %lld seconds elapsed (maximum wait time: %d seconds)";
2026 					}
2027 					snprintf(szBuf,8096,updateTextFormat.c_str(),(long long int)(chrono.getMillis() / 1000),int(readyWaitTimeout / 1000));
2028 
2029 					char szBuf1[8096]="";
2030 					string statusTextFormat = lang.getString("NetworkGameStatusWaiting");
2031 					if(statusTextFormat == "" ||
2032 						statusTextFormat[0] == '?') {
2033 
2034 						statusTextFormat =  "Waiting for players: %s";
2035 					}
2036 					snprintf(szBuf1,8096,statusTextFormat.c_str(),waitForHosts.c_str());
2037 
2038 					logger.add(szBuf, true, szBuf1);
2039 
2040 					uint32 loadingStatus = nmls_NONE;
2041 					//send ready message after, so clients start delayed
2042 					for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
2043 						MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
2044 						ConnectionSlot *connectionSlot= slots[slotIndex];
2045 						if(connectionSlot != NULL && connectionSlot->isConnected() == true) {
2046 							switch(slotIndex) {
2047 								case 0:
2048 									loadingStatus |= nmls_PLAYER1_CONNECTED;
2049 									if(connectionSlot->isReady()) {
2050 										loadingStatus |= nmls_PLAYER1_READY;
2051 									}
2052 									break;
2053 								case 1:
2054 									loadingStatus |= nmls_PLAYER2_CONNECTED;
2055 									if(connectionSlot->isReady()) {
2056 										loadingStatus |= nmls_PLAYER2_READY;
2057 									}
2058 									break;
2059 								case 2:
2060 									loadingStatus |= nmls_PLAYER3_CONNECTED;
2061 									if(connectionSlot->isReady()) {
2062 										loadingStatus |= nmls_PLAYER3_READY;
2063 									}
2064 									break;
2065 								case 3:
2066 									loadingStatus |= nmls_PLAYER4_CONNECTED;
2067 									if(connectionSlot->isReady()) {
2068 										loadingStatus |= nmls_PLAYER4_READY;
2069 									}
2070 									break;
2071 								case 4:
2072 									loadingStatus |= nmls_PLAYER5_CONNECTED;
2073 									if(connectionSlot->isReady()) {
2074 										loadingStatus |= nmls_PLAYER5_READY;
2075 									}
2076 									break;
2077 								case 5:
2078 									loadingStatus |= nmls_PLAYER6_CONNECTED;
2079 									if(connectionSlot->isReady()) {
2080 										loadingStatus |= nmls_PLAYER6_READY;
2081 									}
2082 									break;
2083 								case 6:
2084 									loadingStatus |= nmls_PLAYER7_CONNECTED;
2085 									if(connectionSlot->isReady()) {
2086 										loadingStatus |= nmls_PLAYER7_READY;
2087 									}
2088 									break;
2089 								case 7:
2090 									loadingStatus |= nmls_PLAYER8_CONNECTED;
2091 									if(connectionSlot->isReady()) {
2092 										loadingStatus |= nmls_PLAYER8_READY;
2093 									}
2094 									break;
2095 							}
2096 						}
2097 					}
2098 
2099 					// send loading status message
2100 					for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
2101 						MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
2102 						ConnectionSlot* connectionSlot= slots[slotIndex];
2103 						if(connectionSlot != NULL && connectionSlot->isConnected() == true) {
2104 							NetworkMessageLoadingStatus networkMessageLoadingStatus(loadingStatus);
2105 							connectionSlot->sendMessage(&networkMessageLoadingStatus);
2106 						}
2107 					}
2108 
2109 					sleep(0);
2110 				}
2111 			}
2112 		}
2113 
2114 		Shared::Platform::Window::handleEvent();
2115 	}
2116 
2117 	if(logger.getCancelLoading() == true) {
2118     	Lang &lang= Lang::getInstance();
2119     	const vector<string> languageList = this->gameSettings.getUniqueNetworkPlayerLanguages();
2120     	for(unsigned int langIndex = 0; langIndex < languageList.size(); ++langIndex) {
2121 
2122 			string sErr = lang.getString("GameCancelledByUser",languageList[langIndex]);
2123 			bool localEcho = lang.isLanguageLocal(languageList[langIndex]);
2124 			sendTextMessage(sErr,-1, localEcho,languageList[langIndex]);
2125 
2126 			if(localEcho == true) {
2127 				DisplayErrorMessage(sErr);
2128 			}
2129     	}
2130 		quitGame(true);
2131 		logger.setCancelLoading(false);
2132 		return;
2133 	}
2134 
2135 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s] PART B (telling client we are ready!\n",__FUNCTION__);
2136 	try {
2137 		//send ready message after, so clients start delayed
2138 		for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
2139 
2140 			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
2141 			ConnectionSlot* connectionSlot= slots[slotIndex];
2142 			if(connectionSlot != NULL && connectionSlot->isConnected() == true) {
2143 				NetworkMessageReady networkMessageReady(checksum->getSum());
2144 				connectionSlot->sendMessage(&networkMessageReady);
2145 				connectionSlot->setGameStarted(true);
2146 			}
2147 		}
2148 
2149 		gameStartTime = time(NULL);
2150 	}
2151 	catch(const exception &ex) {
2152 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
2153 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
2154 		DisplayErrorMessage(ex.what());
2155 	}
2156 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s] END\n",__FUNCTION__);
2157 }
2158 
processBroadCastMessageQueue()2159 void ServerInterface::processBroadCastMessageQueue() {
2160 	MutexSafeWrapper safeMutexSlot(broadcastMessageQueueThreadAccessor,CODE_AT_LINE);
2161 	if(broadcastMessageQueue.empty() == false) {
2162 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] broadcastMessageQueue.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,broadcastMessageQueue.size());
2163 		for(int index = 0; index < (int)broadcastMessageQueue.size(); ++index) {
2164 			pair<NetworkMessage *,int> &item = broadcastMessageQueue[index];
2165 			if(item.first != NULL) {
2166 				this->broadcastMessage(item.first,item.second);
2167 				delete item.first;
2168 			}
2169 			item.first = NULL;
2170 		}
2171 		broadcastMessageQueue.clear();
2172 	}
2173 }
2174 
queueBroadcastMessage(NetworkMessage * networkMessage,int excludeSlot)2175 void ServerInterface::queueBroadcastMessage(NetworkMessage *networkMessage, int excludeSlot) {
2176 	MutexSafeWrapper safeMutexSlot(broadcastMessageQueueThreadAccessor,CODE_AT_LINE);
2177 	pair<NetworkMessage*,int> item;
2178 	item.first 	= networkMessage;
2179 	item.second = excludeSlot;
2180 	broadcastMessageQueue.push_back(item);
2181 }
2182 
processTextMessageQueue()2183 void ServerInterface::processTextMessageQueue() {
2184 	MutexSafeWrapper safeMutexSlot(textMessageQueueThreadAccessor,CODE_AT_LINE);
2185 	if(textMessageQueue.empty() == false) {
2186 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] textMessageQueue.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,textMessageQueue.size());
2187 		for(int index = 0; index < (int)textMessageQueue.size(); ++index) {
2188 			TextMessageQueue &item = textMessageQueue[index];
2189 			sendTextMessage(item.text, item.teamIndex, item.echoLocal, item.targetLanguage);
2190 		}
2191 		textMessageQueue.clear();
2192 	}
2193 }
2194 
queueTextMessage(const string & text,int teamIndex,bool echoLocal,string targetLanguage)2195 void ServerInterface::queueTextMessage(const string & text, int teamIndex,
2196 		bool echoLocal, string targetLanguage) {
2197 	//printf("Line: %d text [%s]\n",__LINE__,text.c_str());
2198 
2199 	MutexSafeWrapper safeMutexSlot(textMessageQueueThreadAccessor,CODE_AT_LINE);
2200 	TextMessageQueue item;
2201 	item.text 			= text;
2202 	item.teamIndex 		= teamIndex;
2203 	item.echoLocal 		= echoLocal;
2204 	item.targetLanguage = targetLanguage;
2205 	textMessageQueue.push_back(item);
2206 }
2207 
sendTextMessage(const string & text,int teamIndex,bool echoLocal,string targetLanguage)2208 void ServerInterface::sendTextMessage(const string & text, int teamIndex,
2209 		bool echoLocal,string targetLanguage) {
2210 	sendTextMessage(text, teamIndex, echoLocal, targetLanguage, -1);
2211 }
2212 
sendTextMessage(const string & text,int teamIndex,bool echoLocal,string targetLanguage,int lockedSlotIndex)2213 void ServerInterface::sendTextMessage(const string& text, int teamIndex, bool echoLocal,
2214 		string targetLanguage, int lockedSlotIndex) {
2215 	//printf("Line: %d text [%s] echoLocal = %d\n",__LINE__,text.c_str(),echoLocal);
2216 
2217 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] text [%s] teamIndex = %d, echoLocal = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,text.c_str(),teamIndex,echoLocal,lockedSlotIndex);
2218 
2219 	NetworkMessageText networkMessageText(text, teamIndex, getHumanPlayerIndex(), targetLanguage);
2220 	broadcastMessage(&networkMessageText, -1, lockedSlotIndex);
2221 
2222 	if(echoLocal == true) {
2223 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2224 
2225 		ChatMsgInfo msg(text.c_str(),teamIndex,networkMessageText.getPlayerIndex(), targetLanguage);
2226 		this->addChatInfo(msg);
2227 	}
2228 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2229 }
2230 
sendMarkCellMessage(Vec2i targetPos,int factionIndex,string note,int playerIndex)2231 void ServerInterface::sendMarkCellMessage(Vec2i targetPos, int factionIndex, string note,int playerIndex) {
2232 	sendMarkCellMessage(targetPos, factionIndex, note, playerIndex, -1);
2233 }
2234 
sendMarkCellMessage(Vec2i targetPos,int factionIndex,string note,int playerIndex,int lockedSlotIndex)2235 void ServerInterface::sendMarkCellMessage(Vec2i targetPos, int factionIndex, string note, int playerIndex, int lockedSlotIndex) {
2236 	NetworkMessageMarkCell networkMessageMarkCell(targetPos,factionIndex, note, playerIndex);
2237 	broadcastMessage(&networkMessageMarkCell, -1, lockedSlotIndex);
2238 
2239 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2240 }
2241 
sendHighlightCellMessage(Vec2i targetPos,int factionIndex)2242 void ServerInterface::sendHighlightCellMessage(Vec2i targetPos, int factionIndex) {
2243 	sendHighlightCellMessage(targetPos, factionIndex, -1);
2244 }
2245 
sendHighlightCellMessage(Vec2i targetPos,int factionIndex,int lockedSlotIndex)2246 void ServerInterface::sendHighlightCellMessage(Vec2i targetPos, int factionIndex, int lockedSlotIndex) {
2247 	NetworkMessageHighlightCell networkMessageHighlightCell(targetPos,factionIndex);
2248 	broadcastMessage(&networkMessageHighlightCell, -1, lockedSlotIndex);
2249 
2250 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2251 }
2252 
sendUnMarkCellMessage(Vec2i targetPos,int factionIndex)2253 void ServerInterface::sendUnMarkCellMessage(Vec2i targetPos, int factionIndex) {
2254 	sendUnMarkCellMessage(targetPos, factionIndex, -1);
2255 }
2256 
sendUnMarkCellMessage(Vec2i targetPos,int factionIndex,int lockedSlotIndex)2257 void ServerInterface::sendUnMarkCellMessage(Vec2i targetPos, int factionIndex, int lockedSlotIndex) {
2258 	NetworkMessageUnMarkCell networkMessageMarkCell(targetPos,factionIndex);
2259 	broadcastMessage(&networkMessageMarkCell, -1, lockedSlotIndex);
2260 
2261 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2262 }
2263 
quitGame(bool userManuallyQuit)2264 void ServerInterface::quitGame(bool userManuallyQuit) {
2265 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2266 
2267 	NetworkMessageQuit networkMessageQuit;
2268 	broadcastMessage(&networkMessageQuit);
2269 
2270 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2271 }
2272 
getNetworkStatus()2273 string ServerInterface::getNetworkStatus() {
2274 	Lang &lang = Lang::getInstance();
2275 	string str = "";
2276 	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
2277 		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
2278 		ConnectionSlot *connectionSlot= slots[index];
2279 
2280 		str += intToStr(index)+ ": ";
2281 
2282 		if(connectionSlot!= NULL) {
2283 			if(connectionSlot->isConnected()) {
2284 				int clientLagCount 					= connectionSlot->getCurrentLagCount();
2285 				double lastClientCommandListTimeLag = difftime((long int)time(NULL),connectionSlot->getLastReceiveCommandListTime());
2286 				//float pingTime = connectionSlot->getThreadedPingMS(connectionSlot->getIpAddress().c_str());
2287 				char szBuf[8096]="";
2288 				snprintf(szBuf,8096,", lag = %d [%.2f]",clientLagCount,lastClientCommandListTimeLag);
2289 				str += connectionSlot->getName() + " [" + connectionSlot->getUUID() + "] " + string(szBuf);
2290 			}
2291 		}
2292 		else {
2293 			str += lang.getString("NotConnected");
2294 		}
2295 
2296 		str += '\n';
2297 	}
2298 	return str;
2299 }
2300 
launchGame(const GameSettings * gameSettings)2301 bool ServerInterface::launchGame(const GameSettings *gameSettings) {
2302 	bool bOkToStart = true;
2303 
2304 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2305 
2306 	for(int index = 0; exitServer == false && index < GameConstants::maxPlayers; ++index) {
2307 
2308 		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
2309 		ConnectionSlot *connectionSlot= slots[index];
2310 		if(connectionSlot != NULL &&
2311 		   (connectionSlot->getAllowDownloadDataSynch() == true || connectionSlot->getAllowGameDataSynchCheck() == true) &&
2312 		   connectionSlot->isConnected()) {
2313 
2314 			if(connectionSlot->getNetworkGameDataSynchCheckOk() == false) {
2315 
2316 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] map [%d] tile [%d] techtree [%d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,connectionSlot->getNetworkGameDataSynchCheckOkMap(),connectionSlot->getNetworkGameDataSynchCheckOkTile(),connectionSlot->getNetworkGameDataSynchCheckOkTech());
2317 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] map [%d] tile [%d] techtree [%d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,connectionSlot->getNetworkGameDataSynchCheckOkMap(),connectionSlot->getNetworkGameDataSynchCheckOkTile(),connectionSlot->getNetworkGameDataSynchCheckOkTech());
2318 
2319 				bOkToStart = false;
2320 				break;
2321 			}
2322 		}
2323 	}
2324 	if(bOkToStart == true) {
2325 
2326 		bool useInGameBlockingClientSockets = Config::getInstance().getBool("EnableInGameBlockingSockets","true");
2327 		if(useInGameBlockingClientSockets == true) {
2328 
2329 			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2330 
2331 			for(int index = 0; index < GameConstants::maxPlayers; ++index) {
2332 
2333 				MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[index],CODE_AT_LINE_X(index));
2334 				ConnectionSlot *connectionSlot= slots[index];
2335 				if(connectionSlot != NULL && connectionSlot->isConnected()) {
2336 					connectionSlot->getSocket()->setBlock(true);
2337 				}
2338 			}
2339 		}
2340 
2341 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2342 
2343 		bool requiresUPNPTrigger = false;
2344 		for(int startIndex = 0; startIndex < GameConstants::maxPlayers; ++startIndex) {
2345 
2346 			int factionIndex = gameSettings->getFactionIndexForStartLocation(startIndex);
2347 			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[startIndex],CODE_AT_LINE_X(startIndex));
2348 			ConnectionSlot *connectionSlot= slots[startIndex];
2349 			if((connectionSlot == NULL || connectionSlot->isConnected() == false) &&
2350 				this->getAllowInGameConnections() == true) {
2351 
2352 				// Open slots for joining in progress game
2353 				if(gameSettings->getFactionControl(factionIndex) != ctClosed &&
2354 					gameSettings->getFactionControl(factionIndex) != ctHuman) {
2355 
2356 					//printf("Opening slot for in game connections for slot: %d, faction: %d\n",i,factionIndex);
2357 					if(connectionSlot == NULL) {
2358 						addSlot(startIndex);
2359 						connectionSlot 		= slots[startIndex];
2360 						requiresUPNPTrigger = true;
2361 					}
2362 					connectionSlot->setCanAcceptConnections(true);
2363 				}
2364 			}
2365 		}
2366 
2367 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] needToRepublishToMasterserver = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,needToRepublishToMasterserver);
2368 
2369 		if(this->getAllowInGameConnections() == false) {
2370 			serverSocket.stopBroadCastThread();
2371 		}
2372 
2373 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] needToRepublishToMasterserver = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,needToRepublishToMasterserver);
2374 
2375 		this->gameSettings = *gameSettings;
2376 		//printf("#1 Data synch: lmap %u ltile: %d ltech: %u\n",gameSettings->getMapCRC(),gameSettings->getTilesetCRC(),gameSettings->getTechCRC());
2377 
2378 		NetworkMessageLaunch networkMessageLaunch(gameSettings,nmtLaunch);
2379 		broadcastMessage(&networkMessageLaunch);
2380 
2381 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] needToRepublishToMasterserver = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,needToRepublishToMasterserver);
2382 
2383 		shutdownMasterserverPublishThread();
2384 		MutexSafeWrapper safeMutex(masterServerThreadAccessor,CODE_AT_LINE);
2385 		lastMasterserverHeartbeatTime = 0;
2386 
2387 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ftpServer = %p\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ftpServer);
2388 
2389 		if(this->getAllowInGameConnections() == false) {
2390 			shutdownFTPServer();
2391 		}
2392 
2393 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] needToRepublishToMasterserver = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,needToRepublishToMasterserver);
2394 
2395 		if(publishToMasterserverThread == NULL) {
2396 			if(needToRepublishToMasterserver == true ||
2397 				GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
2398 
2399 				static string mutexOwnerId = string(extractFileFromDirectoryPath(__FILE__).c_str()) + string("_") + intToStr(__LINE__);
2400 				publishToMasterserverThread = new SimpleTaskThread(this,0,125);
2401 				publishToMasterserverThread->setUniqueID(mutexOwnerId);
2402 				publishToMasterserverThread->start();
2403 
2404 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] needToRepublishToMasterserver = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,needToRepublishToMasterserver);
2405 			}
2406 		}
2407 
2408 		if(this->getAllowInGameConnections() == false) {
2409 			shutdownFTPServer();
2410 		}
2411 
2412 		if((needToRepublishToMasterserver == true ||
2413 			GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) &&
2414 		   requiresUPNPTrigger == true) {
2415 
2416             this->getServerSocket()->NETdiscoverUPnPDevices();
2417         }
2418 
2419 		gameLaunched = true;
2420 	}
2421 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2422 
2423 	return bOkToStart;
2424 }
2425 
shutdownFTPServer()2426 void ServerInterface::shutdownFTPServer() {
2427 	if(ftpServer != NULL) {
2428 		ftpServer->shutdownAndWait();
2429 		delete ftpServer;
2430 		ftpServer = NULL;
2431 	}
2432 }
2433 
checkListenerSlots()2434 void ServerInterface::checkListenerSlots() {
2435 	if(gameLaunched == true &&
2436 		this->getAllowInGameConnections() == true) {
2437 
2438 		if(difftime((long int)time(NULL),lastListenerSlotCheckTime) >= 7) {
2439 
2440 			lastListenerSlotCheckTime 			= time(NULL);
2441 			bool useInGameBlockingClientSockets = Config::getInstance().getBool("EnableInGameBlockingSockets","true");
2442 
2443 			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2444 			for(int startIndex = 0; startIndex < GameConstants::maxPlayers; ++startIndex) {
2445 
2446 				int factionIndex = gameSettings.getFactionIndexForStartLocation(startIndex);
2447 				if(gameSettings.getFactionControl(factionIndex) != ctClosed &&
2448 					gameSettings.getFactionControl(factionIndex) != ctHuman) {
2449 
2450 					MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[startIndex],CODE_AT_LINE_X(startIndex));
2451 					ConnectionSlot *connectionSlot= slots[startIndex];
2452 					// Open slots for joining in progress game
2453 					if(connectionSlot == NULL) {
2454 						printf("Opening slot for in game connections, slot: %d, factionindex: %d name: %s\n",startIndex,factionIndex,gameSettings.getFactionTypeName(factionIndex).c_str());
2455 
2456 						addSlot(startIndex);
2457 						connectionSlot = slots[startIndex];
2458 						if(useInGameBlockingClientSockets == true) {
2459 							connectionSlot->getSocket()->setBlock(true);
2460 						}
2461 						connectionSlot->setCanAcceptConnections(true);
2462 					}
2463 					else if(connectionSlot != NULL &&
2464 							connectionSlot->getCanAcceptConnections() == false &&
2465 							connectionSlot->isConnected() == false) {
2466 						printf("Removing slot for in game connections, slot: %d, factionindex: %d name: %s\n",startIndex,factionIndex,gameSettings.getFactionTypeName(factionIndex).c_str());
2467 
2468 						this->removeSlot(startIndex);
2469 					}
2470 				}
2471 			}
2472 		}
2473 	}
2474 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] needToRepublishToMasterserver = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,needToRepublishToMasterserver);
2475 }
2476 
broadcastGameSetup(GameSettings * gameSettingsBuffer,bool setGameSettingsBuffer)2477 void ServerInterface::broadcastGameSetup(GameSettings *gameSettingsBuffer, bool setGameSettingsBuffer) {
2478 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2479 
2480 	if(gameSettingsBuffer == NULL) {
2481 		throw megaglest_runtime_error("gameSettingsBuffer == NULL");
2482 	}
2483 	for(unsigned int factionIndex = 0; factionIndex < (unsigned int)gameSettingsBuffer->getFactionCount(); ++factionIndex) {
2484 
2485 		int slotIndex = gameSettingsBuffer->getStartLocationIndex(factionIndex);
2486 		if(gameSettingsBuffer->getFactionControl(factionIndex) == ctNetwork &&
2487 			isClientConnected(slotIndex) == false) {
2488 
2489 			gameSettingsBuffer->setNetworkPlayerName(factionIndex,GameConstants::NETWORK_SLOT_UNCONNECTED_SLOTNAME);
2490 		}
2491 	}
2492 	if(setGameSettingsBuffer == true) {
2493 		validateGameSettings(gameSettingsBuffer);
2494 	}
2495 
2496 	MutexSafeWrapper safeMutex(serverSynchAccessor,CODE_AT_LINE);
2497 	if(setGameSettingsBuffer == true) {
2498 		gameSettings = *gameSettingsBuffer;
2499 		gameSettingsUpdateCount++;
2500 	}
2501 
2502 	NetworkMessageLaunch networkMessageLaunch(gameSettingsBuffer, nmtBroadCastSetup);
2503 	broadcastMessage(&networkMessageLaunch);
2504 
2505 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2506 }
2507 
broadcastMessage(NetworkMessage * networkMessage,int excludeSlot,int lockedSlotIndex)2508 void ServerInterface::broadcastMessage(NetworkMessage *networkMessage, int excludeSlot, int lockedSlotIndex) {
2509 	try {
2510 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2511 
2512 	    MutexSafeWrapper safeMutexSlotBroadCastAccessor(inBroadcastMessageThreadAccessor,CODE_AT_LINE);
2513 	    if(inBroadcastMessage == true &&
2514 	    	dynamic_cast<NetworkMessageText *>(networkMessage) != NULL) {
2515 
2516 	    	safeMutexSlotBroadCastAccessor.ReleaseLock();
2517 	    	NetworkMessageText *txtMsg = dynamic_cast<NetworkMessageText *>(networkMessage);
2518 	    	if(txtMsg != NULL) {
2519 	    		NetworkMessageText *msgCopy = txtMsg->getCopy();
2520 	    		queueBroadcastMessage(msgCopy, excludeSlot);
2521 	    	}
2522 	    	return;
2523 	    }
2524 	    else {
2525 			inBroadcastMessage = true;
2526 			safeMutexSlotBroadCastAccessor.ReleaseLock(true);
2527 	    }
2528 
2529 		for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
2530 			MutexSafeWrapper safeMutexSlot(NULL,CODE_AT_LINE_X(slotIndex));
2531 			if(slotIndex != lockedSlotIndex) {
2532 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] i = %d, lockedSlotIndex = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slotIndex,lockedSlotIndex);
2533 				safeMutexSlot.setMutex(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
2534 			}
2535 
2536 			ConnectionSlot* connectionSlot= slots[slotIndex];
2537 
2538 			if(slotIndex != excludeSlot && connectionSlot != NULL) {
2539 				if(connectionSlot->isConnected()) {
2540 					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] before sendMessage\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2541 
2542 					connectionSlot->sendMessage(networkMessage);
2543 
2544 					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after sendMessage\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2545 				}
2546 				if(gameHasBeenInitiated == true && connectionSlot->isConnected() == false) {
2547 					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #1 before removeSlot for slot# %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slotIndex);
2548 
2549 					if(this->getAllowInGameConnections() == false) {
2550 						removeSlot(slotIndex,slotIndex);
2551 					}
2552 					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #1 after removeSlot for slot# %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slotIndex);
2553 				}
2554 			}
2555 			else if(slotIndex == excludeSlot && gameHasBeenInitiated == true &&
2556 					connectionSlot != NULL && connectionSlot->isConnected() == false) {
2557 
2558 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #2 before removeSlot for slot# %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slotIndex);
2559 
2560 				if(this->getAllowInGameConnections() == false) {
2561 					removeSlot(slotIndex,slotIndex);
2562 				}
2563 				if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #2 after removeSlot for slot# %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,slotIndex);
2564 			}
2565 		}
2566 
2567 		safeMutexSlotBroadCastAccessor.Lock();
2568 
2569 	    inBroadcastMessage = false;
2570 
2571 	    safeMutexSlotBroadCastAccessor.ReleaseLock();
2572 	}
2573 	catch(const exception &ex) {
2574 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
2575 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ERROR [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
2576 
2577 		MutexSafeWrapper safeMutexSlotBroadCastAccessor(inBroadcastMessageThreadAccessor,CODE_AT_LINE);
2578 	    inBroadcastMessage = false;
2579 	    safeMutexSlotBroadCastAccessor.ReleaseLock();
2580 
2581 		string sMsg = ex.what();
2582 		sendTextMessage(sMsg,-1, true, "", lockedSlotIndex);
2583 	}
2584 }
2585 
broadcastMessageToConnectedClients(NetworkMessage * networkMessage,int excludeSlot)2586 void ServerInterface::broadcastMessageToConnectedClients(NetworkMessage *networkMessage, int excludeSlot) {
2587 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2588 	try {
2589 		for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
2590 			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
2591 			ConnectionSlot *connectionSlot= slots[slotIndex];
2592 
2593 			if(slotIndex != excludeSlot && connectionSlot != NULL) {
2594 				if(connectionSlot->isConnected()) {
2595 					connectionSlot->sendMessage(networkMessage);
2596 				}
2597 			}
2598 		}
2599 	}
2600 	catch(const exception &ex) {
2601 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
2602 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ERROR [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
2603 		DisplayErrorMessage(ex.what());
2604 	}
2605 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2606 }
2607 
updateListen()2608 void ServerInterface::updateListen() {
2609 	if(gameHasBeenInitiated == true &&
2610 		this->getAllowInGameConnections() == false) {
2611 		return;
2612 	}
2613 
2614 	int openSlotCount = 0;
2615 	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex)	{
2616 
2617 		bool isSlotOpen = (slots[slotIndex] != NULL && slots[slotIndex]->isConnected() == false);
2618 		if(isSlotOpen == true) {
2619 			++openSlotCount;
2620 		}
2621 	}
2622 
2623 	serverSocket.listen(openSlotCount);
2624 }
2625 
getOpenSlotCount()2626 int ServerInterface::getOpenSlotCount() {
2627 	int openSlotCount = 0;
2628 	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex)	{
2629 
2630 		bool isSlotOpen = (slots[slotIndex] != NULL && slots[slotIndex]->isConnected() == false);
2631 		if(isSlotOpen == true) {
2632 			++openSlotCount;
2633 		}
2634 	}
2635 	return openSlotCount;
2636 }
2637 
getGameSettingsUpdateCount()2638 int ServerInterface::getGameSettingsUpdateCount() {
2639 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] START gameSettingsUpdateCount = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,gameSettingsUpdateCount);
2640 
2641 	MutexSafeWrapper safeMutex(serverSynchAccessor,CODE_AT_LINE);
2642 	int result = gameSettingsUpdateCount;
2643 	safeMutex.ReleaseLock();
2644 	return result;
2645 }
2646 
validateGameSettings(GameSettings * serverGameSettings)2647 void ServerInterface::validateGameSettings(GameSettings *serverGameSettings) {
2648 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);
2649 
2650 	MutexSafeWrapper safeMutex(serverSynchAccessor,CODE_AT_LINE);
2651 	string mapFile = serverGameSettings->getMap();
2652 	//printf("Trying to set map to [%s]. Current map is [%s]\n",serverGameSettings->getMap().c_str(),gameSettings.getMap().c_str());
2653 	if(gameSettings.getMapFilter()!=serverGameSettings->getMapFilter()){
2654 		if( playerSortedMaps[serverGameSettings->getMapFilter()].size()==0){
2655 			serverGameSettings->setMapFilter(0);
2656 		}
2657 	}
2658 	int playerIndex=serverGameSettings->getMapFilter();
2659 	if(find(playerSortedMaps[playerIndex].begin(),playerSortedMaps[playerIndex].end(),mapFile) == playerSortedMaps[playerIndex].end()) {
2660 		// switch to closest map
2661 		string foundMap = "";
2662 		for (int i = 0 ;i < (int)playerSortedMaps[playerIndex].size(); ++i) {
2663 			foundMap=playerSortedMaps[playerIndex][i];
2664 			if(toLower(foundMap)>toLower(serverGameSettings->getMap())){
2665 				break;
2666 			}
2667 		}
2668 		printf("map %s not found on this server. Switching to map %s\n",serverGameSettings->getMap().c_str(),foundMap.c_str());
2669 		serverGameSettings->setMap(foundMap);
2670 	}
2671 	Checksum checksum;
2672 	string file = Config::getMapPath(serverGameSettings->getMap(),"",false);
2673 	checksum.addFile(file);
2674 	serverGameSettings->setMapCRC(checksum.getSum());
2675 
2676 	string tilesetFile = serverGameSettings->getTileset();
2677 	if(find(tilesetFiles.begin(),tilesetFiles.end(),tilesetFile) == tilesetFiles.end()) {
2678 		printf("Reverting tileset from [%s] to [%s]\n",serverGameSettings->getTileset().c_str(),gameSettings.getTileset().c_str());
2679 
2680 		serverGameSettings->setTileset(gameSettings.getTileset());
2681 		serverGameSettings->setTilesetCRC(gameSettings.getTilesetCRC());
2682 	}
2683 
2684 	string techtreeFile = serverGameSettings->getTech();
2685 	if(find(techTreeFiles.begin(),techTreeFiles.end(),techtreeFile) == techTreeFiles.end()) {
2686 		printf("Reverting tech from [%s] to [%s]\n",serverGameSettings->getTech().c_str(),gameSettings.getTech().c_str());
2687 
2688 		serverGameSettings->setTech(gameSettings.getTech());
2689 		serverGameSettings->setTechCRC(gameSettings.getTechCRC());
2690 	}
2691 }
2692 
setGameSettings(GameSettings * serverGameSettings,bool waitForClientAck)2693 void ServerInterface::setGameSettings(GameSettings *serverGameSettings, bool waitForClientAck) {
2694 	MutexSafeWrapper safeMutex(serverSynchAccessor,CODE_AT_LINE);
2695 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] START gameSettingsUpdateCount = %d, waitForClientAck = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,gameSettingsUpdateCount,waitForClientAck);
2696 
2697 	if(serverGameSettings->getScenario() == "") {
2698 		string mapFile = serverGameSettings->getMap();
2699 		if(find(mapFiles.begin(),mapFiles.end(),mapFile) == mapFiles.end()) {
2700 			printf("Reverting map from [%s] to [%s]\n",serverGameSettings->getMap().c_str(),gameSettings.getMap().c_str());
2701 
2702 			serverGameSettings->setMapFilter(gameSettings.getMapFilter());
2703 			serverGameSettings->setMap(gameSettings.getMap());
2704 			serverGameSettings->setMapCRC(gameSettings.getMapCRC());
2705 		}
2706 
2707 		string tilesetFile = serverGameSettings->getTileset();
2708 		if(find(tilesetFiles.begin(),tilesetFiles.end(),tilesetFile) == tilesetFiles.end()) {
2709 			printf("Reverting tileset from [%s] to [%s]\n",serverGameSettings->getTileset().c_str(),gameSettings.getTileset().c_str());
2710 
2711 			serverGameSettings->setTileset(gameSettings.getTileset());
2712 			serverGameSettings->setTilesetCRC(gameSettings.getTilesetCRC());
2713 		}
2714 
2715 		string techtreeFile = serverGameSettings->getTech();
2716 		if(find(techTreeFiles.begin(),techTreeFiles.end(),techtreeFile) == techTreeFiles.end()) {
2717 			printf("Reverting tech from [%s] to [%s]\n",serverGameSettings->getTech().c_str(),gameSettings.getTech().c_str());
2718 
2719 			serverGameSettings->setTech(gameSettings.getTech());
2720 			serverGameSettings->setTechCRC(gameSettings.getTechCRC());
2721 		}
2722 	}
2723 
2724 	gameSettings = *serverGameSettings;
2725 
2726 	if(getAllowGameDataSynchCheck() == true) {
2727 		if(waitForClientAck == true && gameSettingsUpdateCount > 0) {
2728 			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Waiting for client acks #1\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);
2729 
2730 			time_t tStart = time(NULL);
2731 			bool gotAckFromAllClients = false;
2732 			while(gotAckFromAllClients == false && difftime((long int)time(NULL),tStart) <= 5) {
2733 				gotAckFromAllClients = true;
2734 				for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
2735 					//printf("===> START slot %d - About to setGameSettings #1\n",i);
2736 
2737 					MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
2738 					ConnectionSlot *connectionSlot = slots[slotIndex];
2739 					if(connectionSlot != NULL && connectionSlot->isConnected()) {
2740 						if(connectionSlot->getReceivedNetworkGameStatus() == false) {
2741 							gotAckFromAllClients = false;
2742 						}
2743 
2744 						connectionSlot->update(true,slotIndex);
2745 					}
2746 					//printf("===> END slot %d - About to setGameSettings #1\n",i);
2747 				}
2748 			}
2749 		}
2750 
2751 		for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
2752 			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
2753 			ConnectionSlot *connectionSlot = slots[slotIndex];
2754 			if(connectionSlot != NULL && connectionSlot->isConnected()) {
2755 				connectionSlot->setReceivedNetworkGameStatus(false);
2756 			}
2757 		}
2758 
2759 		NetworkMessageSynchNetworkGameData networkMessageSynchNetworkGameData(getGameSettings());
2760 		broadcastMessageToConnectedClients(&networkMessageSynchNetworkGameData);
2761 
2762 		if(waitForClientAck == true) {
2763 			if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Waiting for client acks #2\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);
2764 
2765 			time_t tStart = time(NULL);
2766 			bool gotAckFromAllClients = false;
2767 			while(gotAckFromAllClients == false && difftime((long int)time(NULL),tStart) <= 5) {
2768 				gotAckFromAllClients = true;
2769 				for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
2770 					//printf("===> START slot %d - About to setGameSettings 2\n",slotIndex);
2771 
2772 					MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
2773 					ConnectionSlot *connectionSlot = slots[slotIndex];
2774 					if(connectionSlot != NULL && connectionSlot->isConnected()) {
2775 						if(connectionSlot->getReceivedNetworkGameStatus() == false) {
2776 							gotAckFromAllClients = false;
2777 						}
2778 
2779 						connectionSlot->update(true,slotIndex);
2780 					}
2781 					//printf("===> END slot %d - About to setGameSettings 2\n",slotIndex);
2782 				}
2783 			}
2784 		}
2785 
2786 	}
2787 	gameSettingsUpdateCount++;
2788 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);
2789 }
2790 
close()2791 void ServerInterface::close() {
2792 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] START\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__);
2793 }
2794 
getHumanPlayerName(int index)2795 string ServerInterface::getHumanPlayerName(int index) {
2796 	string result = Config::getInstance().getString("NetPlayerName", Socket::getHostName().c_str());
2797 	if(index >= 0 || gameSettings.getThisFactionIndex() >= 0) {
2798 		if(index < 0) {
2799 			index = gameSettings.getThisFactionIndex();
2800 		}
2801 		if(gameSettings.getNetworkPlayerName(index) != "") {
2802 			result = gameSettings.getNetworkPlayerName(index);
2803 		}
2804 	}
2805 
2806 	return result;
2807 }
2808 
getHumanPlayerIndex() const2809 int ServerInterface::getHumanPlayerIndex() const {
2810 	return gameSettings.getStartLocationIndex(gameSettings.getThisFactionIndex());
2811 }
2812 
publishToMasterserver()2813 std::map<string,string> ServerInterface::publishToMasterserver() {
2814 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2815 	int slotCountUsed = 1;
2816 	int slotCountHumans = 1;
2817 	int slotCountConnectedPlayers = 1;
2818 
2819 	if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
2820 		slotCountUsed = 0;
2821 		slotCountHumans = 0;
2822 		slotCountConnectedPlayers = 0;
2823 	}
2824 
2825 	Config & config = Config::getInstance();
2826 	std::map < string, string > publishToServerInfo;
2827 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2828 	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
2829 		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
2830 		if(slots[slotIndex] != NULL) {
2831 			slotCountUsed++;
2832 			slotCountHumans++;
2833 			ConnectionSlot* connectionSlot= slots[slotIndex];
2834 			if((connectionSlot!=NULL) && (connectionSlot->isConnected())) {
2835 				slotCountConnectedPlayers++;
2836 			}
2837 		}
2838 	}
2839 	publishToServerInfo["uuid"] 				= Config::getInstance().getString("PlayerId","");
2840 	publishToServerInfo["glestVersion"] 		= glestVersionString;
2841 	publishToServerInfo["platform"] 			= getPlatformNameString() + "-" + getGITRevisionString();
2842 	publishToServerInfo["binaryCompileDate"] 	= getCompileDateTime();
2843 	publishToServerInfo["serverTitle"] 			= this->getGameSettings()->getGameName();
2844 	publishToServerInfo["tech"] 				= this->getGameSettings()->getTech();
2845 	publishToServerInfo["map"] 					= this->getGameSettings()->getMap();
2846 	publishToServerInfo["tileset"] 				= this->getGameSettings()->getTileset();
2847 
2848 	bool updateSlots = true;
2849 	MutexSafeWrapper safeMutex2(gameStatsThreadAccessor,CODE_AT_LINE);
2850 	if(gameStats != NULL) {
2851 		for(int factionIndex = 0; factionIndex < gameStats->getFactionCount(); ++factionIndex) {
2852 			if(gameStats->getVictory(factionIndex) == true) {
2853 				updateSlots = false;
2854 				break;
2855 			}
2856 		}
2857 	}
2858 	safeMutex2.ReleaseLock();
2859 
2860 	if(updateSlots == true) {
2861 		publishToServerInfo["activeSlots"] 		= intToStr(slotCountUsed);
2862 		publishToServerInfo["networkSlots"] 	= intToStr(slotCountHumans);
2863 		publishToServerInfo["connectedClients"] = intToStr(slotCountConnectedPlayers);
2864 	}
2865 
2866 	string serverPort							= config.getString("PortServer", intToStr(GameConstants::serverPort).c_str());
2867 	string externalPort							= config.getString("PortExternal", serverPort.c_str());
2868 	publishToServerInfo["externalconnectport"] 	= externalPort;
2869 	publishToServerInfo["privacyPlease"] 		= intToStr(config.getBool("PrivacyPlease","false"));
2870 	publishToServerInfo["gameStatus"] 			= intToStr(game_status_in_progress);
2871 
2872 	if(publishToMasterserverThread == NULL) {
2873 		publishToServerInfo["gameCmd"]		= "gameOver";
2874 		publishToServerInfo["gameStatus"] 	= intToStr(game_status_finished);
2875 	}
2876 
2877 	//printf("Host game id = %s\n",this->getGameSettings()->getGameUUID().c_str());
2878 	publishToServerInfo["gameUUID"] = this->getGameSettings()->getGameUUID();
2879 
2880 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2881 	return publishToServerInfo;
2882 }
2883 
publishToMasterserverStats()2884 std::map<string,string> ServerInterface::publishToMasterserverStats() {
2885 	if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2886 
2887 	MutexSafeWrapper safeMutex(gameStatsThreadAccessor,CODE_AT_LINE);
2888 	std::map < string, string > publishToServerInfo;
2889 	if(gameStats != NULL) {
2890 		publishToServerInfo["gameUUID"] 						= this->getGameSettings()->getGameUUID();
2891 		publishToServerInfo["tech"] 							= this->getGameSettings()->getTech();
2892 		publishToServerInfo["factionCount"] 					= intToStr(gameStats->getFactionCount());
2893 		publishToServerInfo["framesPlayed"] 					= intToStr(gameStats->getFramesPlayed());
2894 		publishToServerInfo["framesToCalculatePlaytime"] 		= intToStr(gameStats->getFramesToCalculatePlaytime());
2895 		publishToServerInfo["maxConcurrentUnitCount"] 			= intToStr(gameStats->getMaxConcurrentUnitCount());
2896 		publishToServerInfo["totalEndGameConcurrentUnitCount"] 	= intToStr(gameStats->getTotalEndGameConcurrentUnitCount());
2897 		publishToServerInfo["isHeadlessServer"] 				= intToStr(gameStats->getIsMasterserverMode());
2898 
2899 		for(int factionIndex = 0; factionIndex < gameStats->getFactionCount(); ++factionIndex) {
2900 			publishToServerInfo["factionIndex_" + intToStr(factionIndex)] 		= intToStr(factionIndex);
2901 			publishToServerInfo["controlType_" + intToStr(factionIndex)] 		= intToStr(gameStats->getControl(factionIndex));
2902 			publishToServerInfo["resourceMultiplier_" + intToStr(factionIndex)] = floatToStr(gameStats->getResourceMultiplier(factionIndex));
2903 			publishToServerInfo["factionTypeName_" + intToStr(factionIndex)] 	= gameStats->getFactionTypeName(factionIndex);
2904 			publishToServerInfo["personalityType_" + intToStr(factionIndex)] 	= intToStr(gameStats->getPersonalityType(factionIndex));
2905 			publishToServerInfo["teamIndex_" + intToStr(factionIndex)] 			= intToStr(gameStats->getTeam(factionIndex));
2906 			publishToServerInfo["wonGame_" + intToStr(factionIndex)] 			= intToStr(gameStats->getVictory(factionIndex));
2907 			publishToServerInfo["killCount_" + intToStr(factionIndex)] 			= intToStr(gameStats->getKills(factionIndex));
2908 			publishToServerInfo["enemyKillCount_" + intToStr(factionIndex)] 	= intToStr(gameStats->getEnemyKills(factionIndex));
2909 			publishToServerInfo["deathCount_" + intToStr(factionIndex)] 		= intToStr(gameStats->getDeaths(factionIndex));
2910 			publishToServerInfo["unitsProducedCount_" + intToStr(factionIndex)] = intToStr(gameStats->getUnitsProduced(factionIndex));
2911 			publishToServerInfo["resourceHarvestedCount_" + intToStr(factionIndex)] = intToStr(gameStats->getResourcesHarvested(factionIndex));
2912 			publishToServerInfo["playerName_" + intToStr(factionIndex)] 		= gameStats->getPlayerName(factionIndex);
2913 			publishToServerInfo["quitBeforeGameEnd_" + intToStr(factionIndex)] 	= intToStr(gameStats->getPlayerLeftBeforeEnd(factionIndex));
2914 			publishToServerInfo["quitTime_" + intToStr(factionIndex)] 			= intToStr(gameStats->getTimePlayerLeft(factionIndex));
2915 			publishToServerInfo["playerUUID_" + intToStr(factionIndex)] 	    = this->getGameSettings()->getNetworkPlayerUUID(factionIndex);
2916 			publishToServerInfo["platform_" + intToStr(factionIndex)] 	    = this->getGameSettings()->getNetworkPlayerPlatform(factionIndex);
2917 		}
2918 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2919 	}
2920 	return publishToServerInfo;
2921 }
2922 
setGameStats(Stats * stats)2923 void ServerInterface::setGameStats(Stats *stats) {
2924 	if(stats == NULL) {
2925 		return;
2926 	}
2927 	MutexSafeWrapper safeMutex(gameStatsThreadAccessor,CODE_AT_LINE);
2928 	if(gameStats == NULL) {
2929 		gameStats = new Stats();
2930 	}
2931 	*gameStats = *stats;
2932 }
2933 
simpleTask(BaseThread * callingThread,void * userdata)2934 void ServerInterface::simpleTask(BaseThread *callingThread,void *userdata) {
2935 	MutexSafeWrapper safeMutex(masterServerThreadAccessor,CODE_AT_LINE);
2936 
2937 	if(difftime((long int)time(NULL),lastMasterserverHeartbeatTime) >= MASTERSERVER_HEARTBEAT_GAME_STATUS_SECONDS) {
2938 		if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
2939 
2940 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Checking to see masterserver needs an update of the game status [%d] callingThread [%p] publishToMasterserverThread [%p]\n",needToRepublishToMasterserver,callingThread,publishToMasterserverThread);
2941 
2942 		lastMasterserverHeartbeatTime = time(NULL);
2943 		if(needToRepublishToMasterserver == true) {
2944 			try {
2945 				if(Config::getInstance().getString("Masterserver","") != "") {
2946 					string request = Config::getInstance().getString("Masterserver");
2947 					if(request != "") {
2948 						endPathWithSlash(request,false);
2949 					}
2950 					request += "addServerInfo.php?";
2951 
2952 					std::map<string,string> newPublishToServerInfo = publishToMasterserver();
2953 
2954 					CURL *handle = SystemFlags::initHTTP();
2955 					for(std::map<string,string>::const_iterator iterMap = newPublishToServerInfo.begin();
2956 						iterMap != newPublishToServerInfo.end(); ++iterMap) {
2957 
2958 						request += iterMap->first;
2959 						request += "=";
2960 						request += SystemFlags::escapeURL(iterMap->second,handle);
2961 						request += "&";
2962 					}
2963 
2964 					//printf("The Host request is:\n%s\n",request.c_str());
2965 					if(SystemFlags::VERBOSE_MODE_ENABLED) printf("The Host request is:\n%s\n",request.c_str());
2966 
2967 					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d] the request is:\n%s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,request.c_str());
2968 
2969 					if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Calling masterserver [%s]...\n",request.c_str());
2970 
2971 					std::string serverInfo = SystemFlags::getHTTP(request,handle);
2972 					//printf("Result:\n%s\n",serverInfo .c_str());
2973 
2974 					string requestStats = Config::getInstance().getString("Masterserver");
2975 					if(requestStats != "") {
2976 						endPathWithSlash(requestStats,false);
2977 					}
2978 					requestStats += "addGameStats.php?";
2979 
2980 					std::map<string,string> newPublishToServerInfoStats = publishToMasterserverStats();
2981 					if(newPublishToServerInfoStats.empty() == false) {
2982 						for(std::map<string,string>::const_iterator iterMap = newPublishToServerInfoStats.begin();
2983 							iterMap != newPublishToServerInfoStats.end(); ++iterMap) {
2984 
2985 							requestStats += iterMap->first;
2986 							requestStats += "=";
2987 							requestStats += SystemFlags::escapeURL(iterMap->second,handle);
2988 							requestStats += "&";
2989 						}
2990 
2991 						//printf("The Host stats request is:\n%s\n",requestStats.c_str());
2992 						if(SystemFlags::VERBOSE_MODE_ENABLED) printf("The Host request is:\n%s\n",requestStats.c_str());
2993 						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d] the request is:\n%s\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,requestStats.c_str());
2994 						if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Calling masterserver [%s]...\n",requestStats.c_str());
2995 
2996 						std::string serverInfoStats = SystemFlags::getHTTP(requestStats,handle);
2997 						//printf("Result:\n%s\n",serverInfoStats .c_str());
2998 
2999 						if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d] the result is:\n'%s'\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,serverInfoStats.c_str());
3000 					}
3001 
3002 					SystemFlags::cleanupHTTP(&handle);
3003 
3004 					if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Done Calling masterserver\n");
3005 
3006 					//printf("the result is:\n'%s'\n",serverInfo.c_str());
3007 					if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line %d] the result is:\n'%s'\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,serverInfo.c_str());
3008 				}
3009 				else {
3010 					SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line %d] error, no masterserver defined!\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__);
3011 				}
3012 			}
3013 			catch(const exception &ex) {
3014 				SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line %d] error during game status update: [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ex.what());
3015 			}
3016 		}
3017 		if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
3018 			DumpStatsToLog(false);
3019 		}
3020 	}
3021 	if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
3022 		//printf("Attempt Accept\n");
3023 		if(serverSocketAdmin != NULL) {
3024 			Socket *cli = serverSocketAdmin->accept(false);
3025 			if(cli != NULL) {
3026 				printf("Got status request connection, dumping info...\n");
3027 
3028 				string data = DumpStatsToLog(true);
3029 				cli->send(data.c_str(),(int)data.length());
3030 				cli->disconnectSocket();
3031 			}
3032 		}
3033 	}
3034 }
3035 
DumpStatsToLog(bool dumpToStringOnly) const3036 std::string ServerInterface::DumpStatsToLog(bool dumpToStringOnly) const {
3037 	string headlessLogFile = Config::getInstance().getString("HeadlessLogFile","headless.log");
3038 	if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
3039 		headlessLogFile  = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + headlessLogFile ;
3040 	}
3041 	else {
3042         string userData = Config::getInstance().getString("UserData_Root","");
3043         if(userData != "") {
3044         	endPathWithSlash(userData);
3045         }
3046         headlessLogFile  = userData + headlessLogFile ;
3047 	}
3048 
3049 	ostringstream out;
3050 	out << "========================================="  << std::endl;
3051 	out << "Headless Server Current Game information:"  << std::endl;
3052 	out << "========================================="  << std::endl;
3053 
3054 	int connectedSlotCount = 0;
3055 	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
3056 
3057 		MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
3058 		ConnectionSlot *slot = slots[slotIndex];
3059 		if(slot != NULL) {
3060 
3061 			connectedSlotCount++;
3062 			out << "Network connection for index: " << slotIndex << std::endl;
3063 			out << "------------------------------" << std::endl;
3064 			out << "Connected: " << boolToStr(slot->isConnected()) << std::endl;
3065 			out << "Handshake received: " << boolToStr(slot->getConnectHasHandshaked()) << std::endl;
3066 			if(slot->isConnected() == true) {
3067 
3068 				time_t connectTime 	= slot->getConnectedTime();
3069 				//struct tm *loctime 	= localtime (&connectTime);
3070 				struct tm loctime = threadsafe_localtime(connectTime);
3071 				char szBuf[8096]	= "";
3072 				strftime(szBuf,100,"%Y-%m-%d %H:%M:%S",&loctime);
3073 
3074 				const int HOURS_IN_DAY 		= 24;
3075 				const int MINUTES_IN_HOUR 	= 60;
3076 				const int SECONDS_IN_MINUTE = 60;
3077 				int InSeconds 				= difftime((long int)time(NULL),slot->getConnectedTime());
3078 				// compute seconds
3079 				int seconds = InSeconds % SECONDS_IN_MINUTE ;
3080 				// throw away seconds used in previous statement and convert to minutes
3081 				int InMinutes = InSeconds / SECONDS_IN_MINUTE ;
3082 				// compute  minutes
3083 				int minutes = InMinutes % MINUTES_IN_HOUR ;
3084 
3085 				// throw away minutes used in previous statement and convert to hours
3086 				int InHours = InMinutes / MINUTES_IN_HOUR ;
3087 				// compute hours
3088 				int hours = InHours % HOURS_IN_DAY ;
3089 
3090 				out << "Connected at: " 		<< szBuf 					<< std::endl;
3091 				out << "Connection duration: " 	<< hours << " hours " << minutes << " minutes " << seconds << " seconds." << std::endl;
3092 				out << "Player Index: " 		<< slot->getPlayerIndex() 	<< std::endl;
3093 				out << "IP Address: " 			<< slot->getIpAddress() 	<< std::endl;
3094 				out << "Player name: " 			<< slot->getName() 			<< std::endl;
3095 				out << "Player uuid: " 			<< slot->getUUID() 			<< std::endl;
3096 				out << "Language: " 			<< slot->getNetworkPlayerLanguage() << std::endl;
3097 				out << "Game Version: " 		<< slot->getVersionString() << std::endl;
3098 				out << "Session id: " 			<< slot->getSessionKey() 	<< std::endl;
3099 				out << "Socket id: " 			<< slot->getSocketId() 		<< std::endl;
3100 			}
3101 		}
3102 	}
3103 	out << "Total Slot Count: " << connectedSlotCount 	<< std::endl;
3104 	out << "========================================="  << std::endl;
3105 
3106 	std::string result = out.str();
3107 
3108 	if(dumpToStringOnly == false) {
3109 
3110 #if defined(WIN32) && !defined(__MINGW32__)
3111 		FILE *fp = _wfopen(utf8_decode(headlessLogFile ).c_str(), L"w");
3112 		std::ofstream logFile(fp);
3113 #else
3114 		std::ofstream logFile;
3115 		logFile.open(headlessLogFile .c_str(), ios_base::out | ios_base::trunc);
3116 #endif
3117 		logFile << result;
3118 		logFile.close();
3119 #if defined(WIN32) && !defined(__MINGW32__)
3120 		if(fp) {
3121 			fclose(fp);
3122 		}
3123 #endif
3124 	}
3125 
3126     return result;
3127 }
3128 
notifyBadClientConnectAttempt(string ipAddress)3129 void ServerInterface::notifyBadClientConnectAttempt(string ipAddress) {
3130 	//printf("In [%s::%s Line: %d] ipAddress [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,ipAddress.c_str());
3131 
3132 	if(badClientConnectIPList.find(ipAddress) == badClientConnectIPList.end()) {
3133 		badClientConnectIPList[ipAddress] = make_pair(0,(long int)time(NULL));
3134 	}
3135 
3136 	pair<uint64,time_t> &lastBadConnectionAttempt = badClientConnectIPList[ipAddress];
3137 
3138 	const uint64 BLOCK_BAD_CLIENT_CONNECT_MAX_SECONDS 	= Config::getInstance().getInt("BlockBadClientConnectMaxSeconds", "60");
3139 	const uint64 BLOCK_BAD_CLIENT_CONNECT_MAX_ATTEMPTS 	= Config::getInstance().getInt("BlockBadClientConnectMaxAttempts", "6");
3140 	bool addToBlockedClientsList 						= false;
3141 
3142 	if(difftime((long int)time(NULL),lastBadConnectionAttempt.second) <= BLOCK_BAD_CLIENT_CONNECT_MAX_SECONDS) {
3143 
3144 		if(lastBadConnectionAttempt.first+1 > BLOCK_BAD_CLIENT_CONNECT_MAX_ATTEMPTS) {
3145 			addToBlockedClientsList = true;
3146 		}
3147 	}
3148 	else {
3149 		// Reset after x seconds
3150 		lastBadConnectionAttempt.first = 0;
3151 	}
3152 
3153 	if(this->getAllowInGameConnections() == true) {
3154 		printf("notifyBadClientConnectAttempt() #1: %s!\n",ipAddress.c_str());
3155 	}
3156 
3157 	if(addToBlockedClientsList == true) {
3158 		serverSocket.addIPAddressToBlockedList(ipAddress);
3159 	}
3160 
3161 	lastBadConnectionAttempt.first++;
3162 	lastBadConnectionAttempt.second = time(NULL);
3163 }
3164 
getStartInGameConnectionLaunch()3165 bool ServerInterface::getStartInGameConnectionLaunch() {
3166 	bool result = false;
3167 	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
3168 		MutexSafeWrapper safeMutex(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
3169 		if(slots[slotIndex] != NULL) {
3170 
3171 			ConnectionSlot *slot = slots[slotIndex];
3172 			if(slot->getStartInGameConnectionLaunch() == true) {
3173 				result = true;
3174 				break;
3175 			}
3176 		}
3177 	}
3178 	return result;
3179 }
3180 
getPauseForInGameConnection()3181 bool ServerInterface::getPauseForInGameConnection() {
3182 	bool result = false;
3183 	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
3184 		MutexSafeWrapper safeMutex(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
3185 		if(slots[slotIndex] != NULL) {
3186 
3187 			ConnectionSlot *slot = slots[slotIndex];
3188 			if(slot->getPauseForInGameConnection() == true) {
3189 				result = true;
3190 				break;
3191 			}
3192 		}
3193 	}
3194 	return result;
3195 }
3196 
getUnPauseForInGameConnection()3197 bool ServerInterface::getUnPauseForInGameConnection() {
3198 	bool result = false;
3199 	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
3200 		MutexSafeWrapper safeMutex(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
3201 		if(slots[slotIndex] != NULL) {
3202 
3203 			ConnectionSlot *slot = slots[slotIndex];
3204 			if(slot->isConnected() == true) {
3205 				if(slot->isReady() == true) {
3206 					result = true;
3207 					if(slot->getUnPauseForInGameConnection() == false) {
3208 						result = false;
3209 						break;
3210 					}
3211 				}
3212 				else {
3213 					result = false;
3214 					break;
3215 				}
3216 			}
3217 		}
3218 	}
3219 	if(result == true) {
3220 		resumeGameStartTime = time(NULL);
3221 	}
3222 	return result;
3223 }
3224 
findSlotForUUID(string uuid,bool unConnectedOnly)3225 ConnectionSlot * ServerInterface::findSlotForUUID(string uuid, bool unConnectedOnly) {
3226 	ConnectionSlot *result = NULL;
3227 	if(uuid != "") {
3228 		for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
3229 
3230 			MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
3231 			ConnectionSlot *connectionSlot= slots[slotIndex];
3232 
3233 			if(connectionSlot != NULL) {
3234 				if(connectionSlot->getUUID() == uuid) {
3235 					if(unConnectedOnly == false ||
3236 						(unConnectedOnly == true && connectionSlot->isConnected() == false)) {
3237 
3238 						if(result == NULL ||
3239 							(result->getConnectedTime() > connectionSlot->getConnectedTime()))
3240 
3241 						result = connectionSlot;
3242 					}
3243 				}
3244 			}
3245 		}
3246 	}
3247 	return result;
3248 }
3249 
saveGame(XmlNode * rootNode)3250 void ServerInterface::saveGame(XmlNode *rootNode) {
3251 	std::map<string,string> mapTagReplacements;
3252 	XmlNode *serverInterfaceNode = rootNode->addChild("ServerInterface");
3253 
3254 	for(int slotIndex = 0; exitServer == false && slotIndex < GameConstants::maxPlayers; ++slotIndex) {
3255 		MutexSafeWrapper safeMutex(slotAccessorMutexes[slotIndex],CODE_AT_LINE_X(slotIndex));
3256 		if(slots[slotIndex] != NULL) {
3257 
3258 			XmlNode *slotNode = serverInterfaceNode->addChild("Slot");
3259 
3260 			ConnectionSlot *slot = slots[slotIndex];
3261 			if(slot != NULL) {
3262 				slotNode->addAttribute("isconnected",intToStr(slot->isConnected()), mapTagReplacements);
3263 				slotNode->addAttribute("sessionkey",intToStr(slot->getSessionKey()), mapTagReplacements);
3264 				slotNode->addAttribute("ipaddress",slot->getSocket(false)->getIpAddress(), mapTagReplacements);
3265 				slotNode->addAttribute("name",slot->getName(), mapTagReplacements);
3266 				slotNode->addAttribute("uuid",slot->getUUID(), mapTagReplacements);
3267 			}
3268 			else {
3269 				slotNode->addAttribute("isconnected",intToStr(false), mapTagReplacements);
3270 			}
3271 		}
3272 	}
3273 }
3274 
3275 }}//end namespace
3276