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 "connection_slot.h"
13
14 #include "conversion.h"
15 #include "game_util.h"
16 #include "config.h"
17 #include "server_interface.h"
18 #include "network_message.h"
19 #include "platform_util.h"
20 #include <stdexcept>
21
22 #include "leak_dumper.h"
23
24 using namespace std;
25 using namespace Shared::Util;
26
27 namespace Glest{ namespace Game{
28
29 // =====================================================
30 // class ConnectionSlotThread
31 // =====================================================
32
ConnectionSlotThread(int slotIndex)33 ConnectionSlotThread::ConnectionSlotThread(int slotIndex) : BaseThread() {
34 this->masterController = NULL;
35 this->triggerIdMutex = new Mutex(CODE_AT_LINE);
36 this->slotIndex = slotIndex;
37 this->slotInterface = NULL;
38 uniqueID = "ConnectionSlotThread";
39 eventList.clear();
40 eventList.reserve(1000);
41
42 triggerGameStarted = new Mutex(CODE_AT_LINE);
43 gameStarted = false;
44 }
45
ConnectionSlotThread(ConnectionSlotCallbackInterface * slotInterface,int slotIndex)46 ConnectionSlotThread::ConnectionSlotThread(ConnectionSlotCallbackInterface *slotInterface,int slotIndex) : BaseThread() {
47 this->masterController = NULL;
48 this->triggerIdMutex = new Mutex(CODE_AT_LINE);
49 this->slotIndex = slotIndex;
50 this->slotInterface = slotInterface;
51 uniqueID = "ConnectionSlotThread";
52 eventList.clear();
53
54 triggerGameStarted = new Mutex(CODE_AT_LINE);
55 gameStarted = false;
56 }
57
~ConnectionSlotThread()58 ConnectionSlotThread::~ConnectionSlotThread() {
59 delete triggerIdMutex;
60 triggerIdMutex = NULL;
61
62 delete triggerGameStarted;
63 triggerGameStarted = NULL;
64 }
65
setQuitStatus(bool value)66 void ConnectionSlotThread::setQuitStatus(bool value) {
67 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d value = %d\n",__FILE__,__FUNCTION__,__LINE__,value);
68
69 BaseThread::setQuitStatus(value);
70 if(value == true) {
71 signalUpdate(NULL);
72 }
73
74 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
75 }
76
signalUpdate(ConnectionSlotEvent * event)77 void ConnectionSlotThread::signalUpdate(ConnectionSlotEvent *event) {
78 if(event != NULL) {
79 MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE);
80 eventList.push_back(*event);
81 }
82 if(getGameStarted() == true && getQuitStatus() == true) {
83 return;
84 }
85 semTaskSignalled.signal();
86 }
87
setTaskCompleted(int eventId)88 void ConnectionSlotThread::setTaskCompleted(int eventId) {
89 if(eventId > 0) {
90 MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE);
91 for(int index = 0; index < (int)eventList.size(); ++index) {
92 ConnectionSlotEvent &slotEvent = eventList[index];
93 if(slotEvent.eventId == eventId) {
94 slotEvent.eventCompleted = true;
95 break;
96 }
97 }
98 }
99 }
100
purgeAllEvents()101 void ConnectionSlotThread::purgeAllEvents() {
102 MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE);
103 eventList.clear();
104 }
105
setAllEventsCompleted()106 void ConnectionSlotThread::setAllEventsCompleted() {
107 MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE);
108 for(int index = 0; index < (int)eventList.size(); ++index) {
109 ConnectionSlotEvent &slotEvent = eventList[index];
110 if(slotEvent.eventCompleted == false) {
111 slotEvent.eventCompleted = true;
112 }
113 }
114 }
115
purgeCompletedEvents()116 void ConnectionSlotThread::purgeCompletedEvents() {
117 MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE);
118 for(int index = (int)eventList.size() - 1; index >= 0; index--) {
119 ConnectionSlotEvent &slotEvent = eventList[index];
120 if(slotEvent.eventCompleted == true) {
121 eventList.erase(eventList.begin() + index);
122 }
123 }
124 }
125
canShutdown(bool deleteSelfIfShutdownDelayed)126 bool ConnectionSlotThread::canShutdown(bool deleteSelfIfShutdownDelayed) {
127 bool ret = (getExecutingTask() == false);
128 if(ret == false && deleteSelfIfShutdownDelayed == true) {
129 setDeleteSelfOnExecutionDone(deleteSelfIfShutdownDelayed);
130 deleteSelfIfRequired();
131 signalQuit();
132 }
133
134 return ret;
135 }
136
isSignalCompleted(ConnectionSlotEvent * event)137 bool ConnectionSlotThread::isSignalCompleted(ConnectionSlotEvent *event) {
138 bool result = false;
139 if(event != NULL) {
140 MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE);
141 for(int index = 0; index < (int)eventList.size(); ++index) {
142 ConnectionSlotEvent &slotEvent = eventList[index];
143 if(slotEvent.eventId == event->eventId) {
144 result = slotEvent.eventCompleted;
145 break;
146 }
147 }
148 }
149 return result;
150 }
151
slotUpdateTask(ConnectionSlotEvent * event)152 void ConnectionSlotThread::slotUpdateTask(ConnectionSlotEvent *event) {
153 if(event != NULL && event->connectionSlot != NULL) {
154 if(event->eventType == eSendSocketData) {
155 event->connectionSlot->sendMessage(event->networkMessage);
156 }
157 else if(event->eventType == eReceiveSocketData) {
158 event->connectionSlot->updateSlot(event);
159 }
160 }
161 }
162
signalSlave(void * userdata)163 void ConnectionSlotThread::signalSlave(void *userdata) {
164 std::map<int,ConnectionSlotEvent> *eventList = (std::map<int,ConnectionSlotEvent> *)userdata;
165 ConnectionSlotEvent &event = (*eventList)[slotIndex];
166 signalUpdate(&event);
167 }
168
getGameStarted()169 bool ConnectionSlotThread::getGameStarted() {
170 MutexSafeWrapper safeMutexGameStarted(triggerGameStarted,CODE_AT_LINE);
171 return gameStarted;
172 }
setGameStarted(bool value)173 void ConnectionSlotThread::setGameStarted(bool value) {
174 MutexSafeWrapper safeMutexGameStarted(triggerGameStarted,CODE_AT_LINE);
175 if(gameStarted != value) {
176 gameStarted = value;
177
178 if(gameStarted == true) {
179 semTaskSignalled.signal();
180 }
181 }
182 }
183
execute()184 void ConnectionSlotThread::execute() {
185 RunningStatusSafeWrapper runningStatus(this);
186 try {
187 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
188 //printf("Starting client SLOT thread: %d\n",slotIndex);
189
190 for(;this->slotInterface != NULL;) {
191 if(getQuitStatus() == true) {
192 SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
193 break;
194 }
195
196 // Does this game allow joining in progress play and is this slot
197 // not already connected to a client?
198 if( this->slotInterface->getAllowInGameConnections() == true &&
199 this->slotInterface->isClientConnected(slotIndex) == false) {
200 //printf("#1 Non connected slot: %d waiting for client connection..\n",slotIndex);
201 sleep(100);
202
203 if(getQuitStatus() == true) {
204 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
205 break;
206 }
207
208 //printf("Slot thread slotIndex: %d eventCount: %d\n",slotIndex,eventCount);
209
210 ConnectionSlotEvent eventCopy;
211 eventCopy.eventType = eReceiveSocketData;
212 eventCopy.connectionSlot = this->slotInterface->getSlot(slotIndex,true);
213
214 if(getQuitStatus() == true) {
215 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
216 break;
217 }
218
219 ExecutingTaskSafeWrapper safeExecutingTaskMutex(this);
220 this->slotUpdateTask(&eventCopy);
221 }
222 else {
223 // If the game already started?
224 if(getGameStarted() == true) {
225 //printf("#A Checking action for slot: %d\n",slotIndex);
226
227 if(getQuitStatus() == true) {
228 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
229 break;
230 }
231
232 ExecutingTaskSafeWrapper safeExecutingTaskMutex(this);
233
234 // If the slot or socket are NULL the connection was lost
235 // so exit the thread
236 MutexSafeWrapper safeMutex(this->slotInterface->getSlotMutex(slotIndex),CODE_AT_LINE);
237 ConnectionSlot *slot = this->slotInterface->getSlot(slotIndex,false);
238 if(slot == NULL) {
239 break;
240 }
241 Socket *socket = slot->getSocket(true);
242 if(socket == NULL) {
243 break;
244 }
245
246 PLATFORM_SOCKET socketId = socket->getSocketId();
247 safeMutex.ReleaseLock();
248
249 // Avoid mutex locking
250 //bool socketHasReadData = Socket::hasDataToRead(socket->getSocketId());
251 bool socketHasReadData = Socket::hasDataToReadWithWait(socketId,150000);
252
253 if(getQuitStatus() == true) {
254 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
255 break;
256 }
257
258 ConnectionSlotEvent eventCopy;
259 eventCopy.eventType = eReceiveSocketData;
260 eventCopy.connectionSlot = this->slotInterface->getSlot(slotIndex,true);
261 eventCopy.eventId = slotIndex;
262 eventCopy.socketTriggered = socketHasReadData;
263
264 if(getQuitStatus() == true) {
265 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
266 break;
267 }
268
269 this->slotUpdateTask(&eventCopy);
270 }
271 // Game has not yet started
272 else {
273 //printf("#1 Checking action for slot: %d\n",slotIndex);
274
275 if(getGameStarted() == true) {
276 continue;
277 }
278 //printf("#2 Checking action for slot: %d\n",slotIndex);
279
280 semTaskSignalled.waitTillSignalled();
281 //printf("#3 Checking action for slot: %d\n",slotIndex);
282
283 if(getGameStarted() == true) {
284 continue;
285 }
286 //printf("#4 Checking action for slot: %d\n",slotIndex);
287
288 static string masterSlaveOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__);
289 MasterSlaveThreadControllerSafeWrapper safeMasterController(masterController,20000,masterSlaveOwnerId);
290 if(getQuitStatus() == true) {
291 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
292 break;
293 }
294
295 MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE);
296 int eventCount = (int)eventList.size();
297
298 //printf("Slot thread slotIndex: %d eventCount: %d\n",slotIndex,eventCount);
299 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] Slot thread slotIndex: %d eventCount: %d\n",__FILE__,__FUNCTION__,__LINE__,slotIndex,eventCount);
300
301 if(eventCount > 0) {
302 ConnectionSlotEvent eventCopy;
303 for(int i = 0; i < (int)eventList.size(); ++i) {
304 ConnectionSlotEvent &slotEvent = eventList[i];
305 if(slotEvent.eventCompleted == false) {
306 eventCopy = slotEvent;
307 break;
308 }
309 }
310 safeMutex.ReleaseLock();
311
312 if(getQuitStatus() == true) {
313 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
314 break;
315 }
316
317 if(eventCopy.eventId > 0) {
318 ExecutingTaskSafeWrapper safeExecutingTaskMutex(this);
319
320 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] Slot thread slotIndex: %d eventCount: %d eventCopy.eventId: %d\n",__FILE__,__FUNCTION__,__LINE__,slotIndex,eventCount,(int)eventCopy.eventId);
321 //printf("#1 Slot thread slotIndex: %d eventCount: %d eventCopy.eventId: %d\n",slotIndex,eventCount,(int)eventCopy.eventId);
322
323 this->slotUpdateTask(&eventCopy);
324 setTaskCompleted(eventCopy.eventId);
325
326 //printf("#2 Slot thread slotIndex: %d eventCount: %d eventCopy.eventId: %d\n",slotIndex,eventCount,(int)eventCopy.eventId);
327 }
328 }
329 }
330 }
331
332 if(getQuitStatus() == true) {
333 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
334 break;
335 }
336 }
337
338 //printf("Ending client SLOT thread: %d\n",slotIndex);
339
340 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
341 }
342 catch(const exception &ex) {
343
344 SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
345 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
346
347 throw megaglest_runtime_error(ex.what());
348 }
349 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
350 }
351
352 // =====================================================
353 // class ConnectionSlot
354 // =====================================================
355
ConnectionSlot(ServerInterface * serverInterface,int playerIndex)356 ConnectionSlot::ConnectionSlot(ServerInterface* serverInterface, int playerIndex) {
357 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__);
358
359 this->mutexSocket = new Mutex(CODE_AT_LINE);
360 this->socket = NULL;
361 this->mutexCloseConnection = new Mutex(CODE_AT_LINE);
362 this->mutexPendingNetworkCommandList = new Mutex(CODE_AT_LINE);
363 this->socketSynchAccessor = new Mutex(CODE_AT_LINE);
364 this->connectedRemoteIPAddress = 0;
365 this->sessionKey = 0;
366 this->serverInterface = serverInterface;
367 this->playerIndex = playerIndex;
368 this->playerStatus = npst_None;
369 this->playerLanguage = "";
370 this->playerUUID = "";
371 this->platform = "";
372 this->currentFrameCount = 0;
373 this->currentLagCount = 0;
374 this->gotLagCountWarning = false;
375 this->lastReceiveCommandListTime = 0;
376 this->receivedNetworkGameStatus = false;
377
378 this->autoPauseGameCountForLag = 0;
379 this->skipLagCheck = false;
380 this->joinGameInProgress = false;
381 this->canAcceptConnections = true;
382 this->startInGameConnectionLaunch = false;
383 this->pauseForInGameConnection = false;
384 this->unPauseForInGameConnection = false;
385 this->sentSavedGameInfo = false;
386
387 this->ready = false;
388 this->gotIntro = false;
389 this->connectedTime = 0;
390
391 this->networkGameDataSynchCheckOkMap = false;
392 this->networkGameDataSynchCheckOkTile = false;
393 this->networkGameDataSynchCheckOkTech = false;
394 this->setNetworkGameDataSynchCheckTechMismatchReport("");
395 this->setReceivedDataSynchCheck(false);
396
397 this->clearChatInfo();
398
399 this->setSocket(NULL);
400 this->slotThreadWorker = NULL;
401 static string mutexOwnerId = string(extractFileFromDirectoryPath(__FILE__).c_str()) + string("_") + intToStr(__LINE__);
402 this->slotThreadWorker = new ConnectionSlotThread(this->serverInterface,playerIndex);
403 this->slotThreadWorker->setUniqueID(mutexOwnerId);
404 this->slotThreadWorker->start();
405 }
406
~ConnectionSlot()407 ConnectionSlot::~ConnectionSlot() {
408 //printf("===> Destructor for ConnectionSlot = %d\n",playerIndex);
409
410 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] START\n",__FILE__,__FUNCTION__,__LINE__);
411
412 //printf("Deleting connection slot\n");
413 close();
414
415 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
416
417 //printf("#1 Ending client SLOT: %d slotThreadWorker: %p\n",playerIndex,slotThreadWorker);
418 if(slotThreadWorker != NULL) {
419 slotThreadWorker->signalQuit();
420 }
421 if( slotThreadWorker != NULL &&
422 slotThreadWorker->canShutdown(false) == true &&
423 slotThreadWorker->getRunningStatus() == false) {
424 //printf("#2 Ending client SLOT: %d\n",playerIndex);
425
426 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
427
428 delete slotThreadWorker;
429
430 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
431 }
432 else if(slotThreadWorker != NULL &&
433 slotThreadWorker->canShutdown(true) == true) {
434
435 if(slotThreadWorker->getRunningStatus() == false) {
436 //printf("#3 Ending client SLOT: %d\n",playerIndex);
437 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
438
439 delete slotThreadWorker;
440
441 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
442 }
443 else {
444 slotThreadWorker->setDeleteSelfOnExecutionDone(true);
445 slotThreadWorker->setDeleteAfterExecute(true);
446 }
447 }
448 //printf("#4 Ending client SLOT: %d\n",playerIndex);
449 slotThreadWorker = NULL;
450
451 delete socketSynchAccessor;
452 socketSynchAccessor = NULL;
453
454 delete mutexPendingNetworkCommandList;
455 mutexPendingNetworkCommandList = NULL;
456
457 delete mutexCloseConnection;
458 mutexCloseConnection = NULL;
459
460 delete mutexSocket;
461 mutexSocket = NULL;
462
463 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END\n",__FILE__,__FUNCTION__);
464 }
465
getAutoPauseGameCountForLag()466 int ConnectionSlot::getAutoPauseGameCountForLag() {
467 return autoPauseGameCountForLag;
468 }
469
incrementAutoPauseGameCountForLag()470 void ConnectionSlot::incrementAutoPauseGameCountForLag() {
471 autoPauseGameCountForLag++;
472 }
473
getGameStarted()474 bool ConnectionSlot::getGameStarted() {
475 bool result = false;
476 if(this->slotThreadWorker != NULL) {
477 result = this->slotThreadWorker->getGameStarted();
478 }
479 return result;
480 }
setGameStarted(bool value)481 void ConnectionSlot::setGameStarted(bool value) {
482 if(this->slotThreadWorker != NULL) {
483 this->slotThreadWorker->setGameStarted(value);
484 }
485 }
486
setPlayerIndex(int value)487 void ConnectionSlot::setPlayerIndex(int value) {
488 playerIndex = value;
489
490 if(this->slotThreadWorker != NULL) {
491 this->slotThreadWorker->setSlotIndex(playerIndex);
492 }
493 }
494
setReady()495 void ConnectionSlot::setReady() {
496 this->ready= true;
497 this->skipLagCheck = false;
498 this->joinGameInProgress = false;
499 this->sentSavedGameInfo = false;
500 }
501
updateSlot(ConnectionSlotEvent * event)502 void ConnectionSlot::updateSlot(ConnectionSlotEvent *event) {
503 if(event != NULL) {
504 bool &socketTriggered = event->socketTriggered;
505 bool checkForNewClients =
506 (serverInterface->getGameHasBeenInitiated() == false ||
507 serverInterface->getAllowInGameConnections() == true);
508
509 //if((serverInterface->getGameHasBeenInitiated() == false ||
510 // (serverInterface->getAllowInGameConnections() == true && this->isConnected() == false) ||
511 // socketTriggered == true)) {
512 if(socketTriggered == true ||
513 ((serverInterface->getGameHasBeenInitiated() == false ||
514 serverInterface->getAllowInGameConnections() == true) &&
515 this->isConnected() == false)) {
516
517 this->update(checkForNewClients,event->triggerId);
518 }
519 //}
520 }
521 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
522 }
523
getIpAddress(bool mutexLock)524 string ConnectionSlot::getIpAddress(bool mutexLock) {
525 string result = "";
526 MutexSafeWrapper safeMutexSlot((mutexLock == true ? mutexSocket : NULL),CODE_AT_LINE);
527 if(socket != NULL) {
528 result = socket->getIpAddress();
529 }
530 return result;
531 }
532
update(bool checkForNewClients,int lockedSlotIndex)533 void ConnectionSlot::update(bool checkForNewClients,int lockedSlotIndex) {
534 try {
535 clearThreadErrorList();
536
537 if(slotThreadWorker != NULL) {
538 slotThreadWorker->purgeCompletedEvents();
539 }
540
541 pair<bool,Socket*> socketInfo = this->getSocketInfo();
542 if(socketInfo.second == NULL) {
543 if(networkGameDataSynchCheckOkMap) networkGameDataSynchCheckOkMap = false;
544 if(networkGameDataSynchCheckOkTile) networkGameDataSynchCheckOkTile = false;
545 if(networkGameDataSynchCheckOkTech) networkGameDataSynchCheckOkTech = false;
546 this->setReceivedDataSynchCheck(false);
547
548 // Is the listener socket ready to be read?
549 if(checkForNewClients == true && this->canAcceptConnections == true) {
550
551 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] BEFORE accept new client connection, serverInterface->getOpenSlotCount() = %d\n",__FILE__,__FUNCTION__,__LINE__,serverInterface->getOpenSlotCount());
552
553 //printf("Checking for new connections...\n");
554 bool hasData = (serverInterface->getServerSocket() != NULL &&
555 serverInterface->getServerSocket()->hasDataToRead() == true);
556 //printf("Server socket hasData: %d\n",hasData);
557
558 if(hasData == true) {
559 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] about to accept new client connection playerIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex);
560
561 Socket *newSocket = serverInterface->getServerSocket()->accept(false);
562
563 //printf("Server socket newSocket: %p\n",newSocket);
564
565 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] called accept new client connection playerIndex = %d newSocket = %p\n",__FILE__,__FUNCTION__,__LINE__,playerIndex,newSocket);
566 if(newSocket != NULL) {
567 // Set Socket as non-blocking
568 newSocket->setBlock(false);
569
570 MutexSafeWrapper safeMutex(mutexCloseConnection,CODE_AT_LINE);
571 this->setSocket(newSocket);
572 safeMutex.ReleaseLock();
573
574 this->connectedTime = time(NULL);
575 this->clearChatInfo();
576 this->name = "";
577 this->playerStatus = npst_PickSettings;
578 this->playerLanguage = "";
579 this->playerUUID = "";
580 this->platform = "";
581 this->ready = false;
582 this->vctFileList.clear();
583 this->receivedNetworkGameStatus = false;
584 this->gotIntro = false;
585
586 MutexSafeWrapper safeMutexSlot1(mutexPendingNetworkCommandList,CODE_AT_LINE);
587 this->vctPendingNetworkCommandList.clear();
588 safeMutexSlot1.ReleaseLock();
589
590 this->currentFrameCount = 0;
591 this->currentLagCount = 0;
592 this->lastReceiveCommandListTime = 0;
593 this->gotLagCountWarning = false;
594 this->versionString = "";
595
596 serverInterface->updateListen();
597 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex);
598 }
599 else {
600 close();
601 return;
602 }
603
604 //send intro message when connected
605 if(this->isConnected() == true) {
606 //printf("Server socket newSocket is connected: %d\n",playerIndex);
607
608 Chrono seed(true);
609 srand((unsigned int)seed.getCurTicks() / (this->playerIndex + 1));
610
611 sessionKey = rand() % 1000000;
612
613 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] accepted new client connection, serverInterface->getOpenSlotCount() = %d, sessionKey = %d\n",__FILE__,__FUNCTION__,__LINE__,serverInterface->getOpenSlotCount(),sessionKey);
614 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] client will be assigned to the next open slot\n",__FILE__,__FUNCTION__,__LINE__);
615
616 NetworkMessageIntro networkMessageIntro(
617 sessionKey,
618 getNetworkVersionGITString(),
619 getHostName(),
620 playerIndex,
621 nmgstOk,
622 0,
623 ServerSocket::getFTPServerPort(),
624 "",
625 serverInterface->getGameHasBeenInitiated(),
626 Config::getInstance().getString("PlayerId",""),
627 getPlatformNameString());
628 sendMessage(&networkMessageIntro);
629
630 if(this->serverInterface->getGameHasBeenInitiated() == true) {
631 setGameStarted(true);
632 }
633 }
634 }
635 }
636 }
637 else {
638 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
639
640 if(socketInfo.first == true) {
641 this->clearChatInfo();
642
643 bool gotTextMsg = true;
644 bool gotCellMarkerMsg = true;
645 bool waitForLaggingClient = false;
646 bool waitedForLaggingClient = false;
647
648 //printf("Update slot: %d this->hasDataToRead(): %d\n",this->playerIndex,this->hasDataToRead());
649
650 for(;waitForLaggingClient == true ||
651 (this->hasDataToRead() == true &&
652 (gotTextMsg == true || gotCellMarkerMsg == true));) {
653
654 //printf("Server slot checking for waitForLaggingClient = %d this->hasDataToRead() = %d gotTextMsg = %d gotCellMarkerMsg = %d\n",waitForLaggingClient,this->hasDataToRead(),gotTextMsg,gotCellMarkerMsg);
655
656 waitForLaggingClient = false;
657 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] polling for networkMessageType...\n",__FILE__,__FUNCTION__,__LINE__);
658
659 NetworkMessageType networkMessageType= getNextMessageType();
660
661 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] networkMessageType = %d\n",__FILE__,__FUNCTION__,__LINE__,networkMessageType);
662
663 gotTextMsg = false;
664 gotCellMarkerMsg = false;
665 //process incoming commands
666 switch(networkMessageType) {
667
668 case nmtInvalid:
669 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtInvalid\n",__FILE__,__FUNCTION__,__LINE__);
670 break;
671
672 case nmtPing:
673 {
674 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtPing\n",__FILE__,__FUNCTION__);
675
676 // client REQUIRES a ping before completing intro
677 // authentication
678 NetworkMessagePing networkMessagePing;
679 if(receiveMessage(&networkMessagePing)) {
680 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
681 lastPingInfo = networkMessagePing;
682 }
683 else {
684 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
685 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
686 close();
687 return;
688 }
689 }
690 break;
691
692 case nmtText:
693 {
694 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtText gotIntro = %d\n",__FILE__,__FUNCTION__,__LINE__,gotIntro);
695
696 if(gotIntro == true) {
697 NetworkMessageText networkMessageText;
698 if(receiveMessage(&networkMessageText)) {
699 ChatMsgInfo msg(networkMessageText.getText().c_str(),networkMessageText.getTeamIndex(),networkMessageText.getPlayerIndex(),networkMessageText.getTargetLanguage());
700 this->addChatInfo(msg);
701 gotTextMsg = true;
702 }
703 else {
704 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
705 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
706 close();
707 return;
708 }
709 }
710 else {
711 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
712 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
713 close();
714 return;
715 }
716 }
717 break;
718
719 case nmtMarkCell:
720 {
721 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtMarkCell gotIntro = %d\n",__FILE__,__FUNCTION__,__LINE__,gotIntro);
722
723 if(gotIntro == true) {
724 NetworkMessageMarkCell networkMessageMarkCell;
725 if(receiveMessage(&networkMessageMarkCell)) {
726 MarkedCell msg(networkMessageMarkCell.getTarget(),
727 networkMessageMarkCell.getFactionIndex(),
728 networkMessageMarkCell.getText().c_str(),
729 networkMessageMarkCell.getPlayerIndex());
730
731 this->addMarkedCell(msg);
732 gotCellMarkerMsg = true;
733 }
734 else {
735 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
736 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
737 close();
738 return;
739 }
740 }
741 else {
742 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
743 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
744 close();
745 return;
746 }
747 }
748 break;
749
750 case nmtUnMarkCell:
751 {
752 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtUnMarkCell gotIntro = %d\n",__FILE__,__FUNCTION__,__LINE__,gotIntro);
753
754 if(gotIntro == true) {
755 NetworkMessageUnMarkCell networkMessageMarkCell;
756 if(receiveMessage(&networkMessageMarkCell)) {
757 UnMarkedCell msg(networkMessageMarkCell.getTarget(),
758 networkMessageMarkCell.getFactionIndex());
759
760 this->addUnMarkedCell(msg);
761 gotCellMarkerMsg = true;
762 }
763 else {
764 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
765 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
766 close();
767 return;
768 }
769 }
770 else {
771 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
772 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
773 close();
774 return;
775 }
776 }
777 break;
778
779 case nmtHighlightCell:
780 {
781 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtMarkCell gotIntro = %d\n",__FILE__,__FUNCTION__,__LINE__,gotIntro);
782
783 if(gotIntro == true) {
784 NetworkMessageHighlightCell networkMessageHighlightCell;
785 if(receiveMessage(&networkMessageHighlightCell)) {
786 MarkedCell msg(networkMessageHighlightCell.getTarget(),
787 networkMessageHighlightCell.getFactionIndex(),"none",-1);
788
789 this->setHighlightedCell(msg);
790 gotCellMarkerMsg = true;
791 }
792 else {
793 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
794 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
795 close();
796 return;
797 }
798 }
799 else {
800 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
801 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
802 close();
803 return;
804 }
805 }
806 break;
807
808 //command list
809 case nmtCommandList: {
810
811 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtCommandList gotIntro = %d\n",__FILE__,__FUNCTION__,__LINE__,gotIntro);
812
813 if(gotIntro == true) {
814 NetworkMessageCommandList networkMessageCommandList;
815 if(receiveMessage(&networkMessageCommandList)) {
816 currentFrameCount = networkMessageCommandList.getFrameCount();
817 lastReceiveCommandListTime = time(NULL);
818
819 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] currentFrameCount = %d\n",__FILE__,__FUNCTION__,__LINE__,currentFrameCount);
820
821 MutexSafeWrapper safeMutexSlot(mutexPendingNetworkCommandList,CODE_AT_LINE);
822 for(int i = 0; i < networkMessageCommandList.getCommandCount(); ++i) {
823 vctPendingNetworkCommandList.push_back(*networkMessageCommandList.getCommand(i));
824 }
825 //printf("Got commands from client frame: %d count: %d\n",currentFrameCount,vctPendingNetworkCommandList.size());
826
827 //printf("#2 Server slot got currentFrameCount = %d\n",currentFrameCount);
828 }
829 else {
830 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
831 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
832 close();
833 return;
834 }
835 }
836 else {
837 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
838 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
839 close();
840 return;
841 }
842 }
843 break;
844
845 //process intro messages
846 case nmtIntro:
847 {
848 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtIntro\n",__FILE__,__FUNCTION__);
849
850 NetworkMessageIntro networkMessageIntro;
851 if(receiveMessage(&networkMessageIntro)) {
852 int32 msgSessionId = networkMessageIntro.getSessionId();
853 this->name= networkMessageIntro.getName();
854 this->versionString = networkMessageIntro.getVersionString();
855 this->connectedRemoteIPAddress = networkMessageIntro.getExternalIp();
856 this->playerLanguage = networkMessageIntro.getPlayerLanguage();
857 this->playerUUID = networkMessageIntro.getPlayerUUID();
858 this->platform = networkMessageIntro.getPlayerPlatform();
859
860 //printf("Got uuid from client [%s]\n",this->playerUUID.c_str());
861 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got name [%s] versionString [%s], msgSessionId = %d\n",__FILE__,__FUNCTION__,name.c_str(),versionString.c_str(),msgSessionId);
862
863 if(msgSessionId != sessionKey) {
864 string playerNameStr = name;
865 string sErr = "Client gave invalid sessionid for player [" + playerNameStr + "] actual [" + intToStr(msgSessionId) + "] expected [" + intToStr(sessionKey) + "]";
866 printf("%s\n",sErr.c_str());
867 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str());
868
869 close();
870 return;
871 }
872 else if(this->playerUUID == "") {
873 string playerNameStr = name;
874 string sErr = "Client gave an invalid UUID for player [" + playerNameStr + "]";
875 printf("%s\n",sErr.c_str());
876 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str());
877
878 close();
879 return;
880 }
881 else {
882 //check consistency
883 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
884
885 bool compatible = checkVersionComptability(getNetworkVersionGITString(), networkMessageIntro.getVersionString());
886
887 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
888
889 if(compatible == false) {
890 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
891
892 bool versionMatched = false;
893 string platformFreeVersion = getNetworkPlatformFreeVersionString();
894 string sErr = "";
895
896 if(strncmp(platformFreeVersion.c_str(),networkMessageIntro.getVersionString().c_str(),strlen(platformFreeVersion.c_str())) != 0) {
897 string playerNameStr = name;
898 sErr = "Server and client binary mismatch!\nYou have to use the exactly same binaries!\n\nServer: " + getNetworkVersionGITString() +
899 "\nClient: " + networkMessageIntro.getVersionString() + " player [" + playerNameStr + "]";
900 printf("%s\n",sErr.c_str());
901
902 serverInterface->sendTextMessage("Server and client binary mismatch!!",-1, true,"",lockedSlotIndex);
903 serverInterface->sendTextMessage(" Server:" + getNetworkVersionGITString(),-1, true,"",lockedSlotIndex);
904 serverInterface->sendTextMessage(" Client: "+ networkMessageIntro.getVersionString(),-1, true,"",lockedSlotIndex);
905 serverInterface->sendTextMessage(" Client player [" + playerNameStr + "]",-1, true,"",lockedSlotIndex);
906 }
907 else {
908 versionMatched = true;
909
910 string playerNameStr = name;
911 sErr = "Warning, Server and client are using the same version but different platforms.\n\nServer: " + getNetworkVersionGITString() +
912 "\nClient: " + networkMessageIntro.getVersionString() + " player [" + playerNameStr + "]";
913 //printf("%s\n",sErr.c_str());
914 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str());
915 }
916
917 if(Config::getInstance().getBool("PlatformConsistencyChecks","true") &&
918 versionMatched == false) { // error message and disconnect only if checked
919 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str());
920 close();
921 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str());
922 return;
923 }
924 }
925
926 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
927 gotIntro = true;
928
929 int factionIndex = this->serverInterface->gameSettings.getFactionIndexForStartLocation(playerIndex);
930 this->serverInterface->addClientToServerIPAddress(this->getSocket()->getConnectedIPAddress(this->getSocket()->getIpAddress()),this->connectedRemoteIPAddress);
931
932 this->serverInterface->gameSettings.setNetworkPlayerUUID(factionIndex,this->playerUUID);
933 this->serverInterface->gameSettings.setNetworkPlayerPlatform(factionIndex,this->platform);
934
935 if(serverInterface->getGameHasBeenInitiated() == true &&
936 serverInterface->getAllowInGameConnections() == true) {
937 this->serverInterface->gameSettings.setNetworkPlayerStatuses(factionIndex,npst_None);
938 }
939
940 if(getAllowGameDataSynchCheck() == true && serverInterface->getGameSettings() != NULL) {
941 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] sending NetworkMessageSynchNetworkGameData\n",__FILE__,__FUNCTION__,__LINE__);
942
943 NetworkMessageSynchNetworkGameData networkMessageSynchNetworkGameData(serverInterface->getGameSettings());
944 sendMessage(&networkMessageSynchNetworkGameData);
945 }
946
947 if(serverInterface->getGameHasBeenInitiated() == true &&
948 serverInterface->getAllowInGameConnections() == true) {
949
950 ConnectionSlot *slot = serverInterface->findSlotForUUID(this->playerUUID,true);
951 if(slot != NULL) {
952 slot->setJoinGameInProgressFlags();
953 slot->setPauseForInGameConnection(true);
954
955 serverInterface->switchSlot(this->playerIndex,slot->getPlayerIndex());
956 }
957 else {
958 setJoinGameInProgressFlags();
959 this->setPauseForInGameConnection(true);
960 }
961 }
962 else {
963 ConnectionSlot *slot = serverInterface->findSlotForUUID(this->playerUUID,true);
964 if(slot != NULL) {
965 serverInterface->switchSlot(this->playerIndex,slot->getPlayerIndex());
966 }
967 }
968 }
969 }
970 else {
971 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
972 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
973 close();
974 return;
975 }
976 }
977 break;
978
979 case nmtLaunch:
980 case nmtBroadCastSetup:
981 {
982 if(gotIntro == true) {
983 if(this->serverInterface->getGameSettings() == NULL ||
984 (joinGameInProgress == false && sessionKey != this->serverInterface->getGameSettings()->getMasterserver_admin())) {
985 string playerNameStr = name;
986 string sErr = "Client has invalid admin sessionid for player [" + playerNameStr + "]";
987 printf("%s\n",sErr.c_str());
988 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str());
989
990 close();
991 return;
992 }
993
994 NetworkMessageLaunch networkMessageLaunch;
995 if(receiveMessage(&networkMessageLaunch,networkMessageType)) {
996 if(networkMessageLaunch.getMessageType() == nmtLaunch) {
997 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got nmtLaunch\n",__FILE__,__FUNCTION__,__LINE__);
998 //printf("Got launch request from client joinGameInProgress = %d joinGameInProgress = %d!\n",joinGameInProgress,joinGameInProgress);
999 }
1000 else if(networkMessageLaunch.getMessageType() == nmtBroadCastSetup) {
1001 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got nmtBroadCastSetup\n",__FILE__,__FUNCTION__,__LINE__);
1002 }
1003 else {
1004 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got networkMessageLaunch.getMessageType() = %d\n",__FILE__,__FUNCTION__,__LINE__,networkMessageLaunch.getMessageType());
1005
1006 char szBuf[1024]="";
1007 snprintf(szBuf,1023,"In [%s::%s Line: %d] Invalid networkMessageLaunch.getMessageType() = %d",__FILE__,__FUNCTION__,__LINE__,networkMessageLaunch.getMessageType());
1008 throw megaglest_runtime_error(szBuf);
1009 }
1010
1011 int minHeadLessPlayersRequired = Config::getInstance().getInt("MinHeadlessPlayersRequired","2");
1012 if(this->joinGameInProgress == false &&
1013 networkMessageLaunch.getMessageType() == nmtLaunch &&
1014 this->ready == false &&
1015 this->serverInterface->getConnectedSlotCount(true) < minHeadLessPlayersRequired) {
1016
1017 Lang &lang= Lang::getInstance();
1018 const vector<string> languageList = this->serverInterface->getGameSettings()->getUniqueNetworkPlayerLanguages();
1019 for(unsigned int index = 0; index < languageList.size(); ++index) {
1020 char szBuf[4096]="";
1021 string msgTemplate = "You must have have at least %d player(s) connected to start this game!";
1022 if(lang.hasString("HeadlessAdminRequiresMorePlayers",languageList[index]) == true) {
1023 msgTemplate = lang.getString("HeadlessAdminRequiresMorePlayers",languageList[index]);
1024 }
1025 #ifdef WIN32
1026 _snprintf(szBuf,4095,msgTemplate.c_str(),minHeadLessPlayersRequired);
1027 #else
1028 snprintf(szBuf,4095,msgTemplate.c_str(),minHeadLessPlayersRequired);
1029 #endif
1030 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,szBuf);
1031
1032 string sMsg = szBuf;
1033 bool echoLocal = lang.isLanguageLocal(languageList[index]);
1034 this->serverInterface->sendTextMessage(sMsg,-1, echoLocal, languageList[index], this->getPlayerIndex());
1035 }
1036 }
1037 else {
1038 if(this->joinGameInProgress == false) {
1039 GameSettings gameSettingsBuffer;
1040 networkMessageLaunch.buildGameSettings(&gameSettingsBuffer);
1041
1042 //printf("Connection slot got networkMessageLaunch.getMessageType() = %d, got map [%s]\n",networkMessageLaunch.getMessageType(),gameSettings.getMap().c_str());
1043 //printf("\n\n\n\n=====Connection slot got settings:\n%s\n",gameSettings.toString().c_str());
1044
1045 this->serverInterface->broadcastGameSetup(&gameSettingsBuffer, true);
1046 }
1047
1048 if(this->joinGameInProgress == false &&
1049 networkMessageLaunch.getMessageType() == nmtLaunch) {
1050
1051 this->serverInterface->setMasterserverAdminRequestLaunch(true);
1052 }
1053 else if(this->joinGameInProgress == true &&
1054 networkMessageLaunch.getMessageType() == nmtLaunch) {
1055 //printf("!!! setStartInGameConnectionLaunch for client joinGameInProgress = %d!\n",joinGameInProgress);
1056
1057 int factionIndex = this->serverInterface->gameSettings.getFactionIndexForStartLocation(playerIndex);
1058 this->serverInterface->gameSettings.setFactionControl(factionIndex,ctNetwork);
1059 this->serverInterface->gameSettings.setNetworkPlayerName(factionIndex,this->name);
1060 this->serverInterface->gameSettings.setNetworkPlayerUUID(factionIndex,this->playerUUID);
1061 this->serverInterface->gameSettings.setNetworkPlayerPlatform(factionIndex,this->platform);
1062
1063 if(this->serverInterface->gameSettings.getNetworkPlayerStatuses(factionIndex) == npst_Disconnected) {
1064 this->serverInterface->gameSettings.setNetworkPlayerStatuses(factionIndex,npst_None);
1065 }
1066
1067 this->serverInterface->broadcastGameSetup(&this->serverInterface->gameSettings, true);
1068
1069 this->setStartInGameConnectionLaunch(true);
1070 }
1071 }
1072 }
1073 else {
1074 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
1075 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
1076 close();
1077 return;
1078 }
1079 }
1080 else {
1081 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
1082 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
1083 close();
1084 return;
1085 }
1086 }
1087 break;
1088
1089 //process datasynch messages
1090 case nmtSynchNetworkGameDataStatus:
1091 {
1092 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtSynchNetworkGameDataStatus, gotIntro = %d\n",__FILE__,__FUNCTION__,__LINE__,gotIntro);
1093
1094 if(gotIntro == true) {
1095 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1096
1097 NetworkMessageSynchNetworkGameDataStatus networkMessageSynchNetworkGameDataStatus;
1098 if(receiveMessage(&networkMessageSynchNetworkGameDataStatus)) {
1099 this->setNetworkGameDataSynchCheckTechMismatchReport("");
1100 this->setReceivedDataSynchCheck(false);
1101
1102 Config &config = Config::getInstance();
1103 string scenarioDir = "";
1104 if(serverInterface->getGameSettings()->getScenarioDir() != "") {
1105 scenarioDir = serverInterface->getGameSettings()->getScenarioDir();
1106 if(EndsWith(scenarioDir, ".xml") == true) {
1107 scenarioDir = scenarioDir.erase(scenarioDir.size() - 4, 4);
1108 scenarioDir = scenarioDir.erase(scenarioDir.size() - serverInterface->getGameSettings()->getScenario().size(), serverInterface->getGameSettings()->getScenario().size() + 1);
1109 }
1110
1111 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] gameSettings.getScenarioDir() = [%s] gameSettings.getScenario() = [%s] scenarioDir = [%s]\n",__FILE__,__FUNCTION__,__LINE__,serverInterface->getGameSettings()->getScenarioDir().c_str(),serverInterface->getGameSettings()->getScenario().c_str(),scenarioDir.c_str());
1112 }
1113
1114 //tileset
1115 uint32 tilesetCRC = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptTilesets,scenarioDir), string("/") + serverInterface->getGameSettings()->getTileset() + string("/*"), ".xml", NULL);
1116 uint32 techCRC = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptTechs,scenarioDir), "/" + serverInterface->getGameSettings()->getTech() + "/*", ".xml", NULL);
1117 Checksum checksum;
1118 string file = Config::getMapPath(serverInterface->getGameSettings()->getMap(),scenarioDir,false);
1119 checksum.addFile(file);
1120 uint32 mapCRC = checksum.getSum();
1121
1122 networkGameDataSynchCheckOkMap = (networkMessageSynchNetworkGameDataStatus.getMapCRC() == mapCRC);
1123 networkGameDataSynchCheckOkTile = (networkMessageSynchNetworkGameDataStatus.getTilesetCRC() == tilesetCRC);
1124 networkGameDataSynchCheckOkTech = (networkMessageSynchNetworkGameDataStatus.getTechCRC() == techCRC);
1125
1126 // For testing
1127 //techCRC++;
1128
1129 if( networkGameDataSynchCheckOkMap == true &&
1130 networkGameDataSynchCheckOkTile == true &&
1131 networkGameDataSynchCheckOkTech == true) {
1132 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] client data synch ok\n",__FILE__,__FUNCTION__);
1133 }
1134 else {
1135 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] mapCRC = %d, remote = %d\n",__FILE__,__FUNCTION__,mapCRC,networkMessageSynchNetworkGameDataStatus.getMapCRC());
1136 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] tilesetCRC = %d, remote = %d\n",__FILE__,__FUNCTION__,tilesetCRC,networkMessageSynchNetworkGameDataStatus.getTilesetCRC());
1137 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] techCRC = %d, remote = %d\n",__FILE__,__FUNCTION__,techCRC,networkMessageSynchNetworkGameDataStatus.getTechCRC());
1138
1139 if(allowDownloadDataSynch == true) {
1140 // Now get all filenames with their CRC values and send to the client
1141 vctFileList.clear();
1142
1143 Config &config = Config::getInstance();
1144 string scenarioDir = "";
1145 if(serverInterface->getGameSettings()->getScenarioDir() != "") {
1146 scenarioDir = serverInterface->getGameSettings()->getScenarioDir();
1147 if(EndsWith(scenarioDir, ".xml") == true) {
1148 scenarioDir = scenarioDir.erase(scenarioDir.size() - 4, 4);
1149 scenarioDir = scenarioDir.erase(scenarioDir.size() - serverInterface->getGameSettings()->getScenario().size(), serverInterface->getGameSettings()->getScenario().size() + 1);
1150 }
1151
1152 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] gameSettings.getScenarioDir() = [%s] gameSettings.getScenario() = [%s] scenarioDir = [%s]\n",__FILE__,__FUNCTION__,__LINE__,serverInterface->getGameSettings()->getScenarioDir().c_str(),serverInterface->getGameSettings()->getScenario().c_str(),scenarioDir.c_str());
1153 }
1154
1155 if(networkGameDataSynchCheckOkTile == false) {
1156 if(tilesetCRC == 0) {
1157 vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTilesets,scenarioDir), string("/") + serverInterface->getGameSettings()->getTileset() + string("/*"), "", &vctFileList);
1158 }
1159 else {
1160 vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTilesets,scenarioDir), "/" + serverInterface->getGameSettings()->getTileset() + "/*", ".xml", &vctFileList);
1161 }
1162 }
1163 if(networkGameDataSynchCheckOkTech == false) {
1164 if(techCRC == 0) {
1165 vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTechs,scenarioDir),"/" + serverInterface->getGameSettings()->getTech() + "/*", "", &vctFileList);
1166 }
1167 else {
1168 vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTechs,scenarioDir),"/" + serverInterface->getGameSettings()->getTech() + "/*", ".xml", &vctFileList);
1169 }
1170
1171 string report = networkMessageSynchNetworkGameDataStatus.getTechCRCFileMismatchReport(serverInterface->getGameSettings()->getTech(),vctFileList);
1172 this->setNetworkGameDataSynchCheckTechMismatchReport(report);
1173 }
1174 if(networkGameDataSynchCheckOkMap == false) {
1175 vctFileList.push_back(std::pair<string,uint32>(Config::getMapPath(serverInterface->getGameSettings()->getMap(),scenarioDir,false),mapCRC));
1176 }
1177
1178 NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck((int)vctFileList.size(), 1, vctFileList[0].second, vctFileList[0].first);
1179 sendMessage(&networkMessageSynchNetworkGameDataFileCRCCheck);
1180 }
1181 else {
1182 if(networkGameDataSynchCheckOkTech == false) {
1183 vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTechs,scenarioDir),"/" + serverInterface->getGameSettings()->getTech() + "/*", ".xml", NULL);
1184
1185 string report = networkMessageSynchNetworkGameDataStatus.getTechCRCFileMismatchReport(serverInterface->getGameSettings()->getTech(),vctFileList);
1186 this->setNetworkGameDataSynchCheckTechMismatchReport(report);
1187 }
1188 }
1189 }
1190
1191 this->setReceivedDataSynchCheck(true);
1192 receivedNetworkGameStatus = true;
1193 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1194 }
1195 else {
1196 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
1197 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
1198 close();
1199 return;
1200 }
1201 }
1202 else {
1203 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
1204 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
1205 close();
1206 return;
1207 }
1208 }
1209 break;
1210
1211 case nmtSynchNetworkGameDataFileCRCCheck:
1212 {
1213
1214 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtSynchNetworkGameDataFileCRCCheck\n",__FILE__,__FUNCTION__);
1215
1216 if(gotIntro == true) {
1217 NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck;
1218 if(receiveMessage(&networkMessageSynchNetworkGameDataFileCRCCheck))
1219 {
1220 int fileIndex = networkMessageSynchNetworkGameDataFileCRCCheck.getFileIndex();
1221 NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck((int)vctFileList.size(), fileIndex, vctFileList[fileIndex-1].second, vctFileList[fileIndex-1].first);
1222 sendMessage(&networkMessageSynchNetworkGameDataFileCRCCheck);
1223 }
1224 else {
1225 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
1226 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
1227 close();
1228 return;
1229 }
1230 }
1231 else {
1232 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
1233 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
1234 close();
1235 return;
1236 }
1237 }
1238 break;
1239
1240 case nmtSynchNetworkGameDataFileGet:
1241 {
1242
1243 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtSynchNetworkGameDataFileGet\n",__FILE__,__FUNCTION__);
1244
1245 if(gotIntro == true) {
1246 NetworkMessageSynchNetworkGameDataFileGet networkMessageSynchNetworkGameDataFileGet;
1247 if(receiveMessage(&networkMessageSynchNetworkGameDataFileGet)) {
1248 FileTransferInfo fileInfo;
1249 fileInfo.hostType = eServer;
1250 //fileInfo.serverIP = this->ip.getString();
1251 fileInfo.serverPort = Config::getInstance().getInt("PortServer",intToStr(GameConstants::serverPort).c_str());
1252 fileInfo.fileName = networkMessageSynchNetworkGameDataFileGet.getFileName();
1253
1254 FileTransferSocketThread *fileXferThread = new FileTransferSocketThread(fileInfo);
1255 fileXferThread->start();
1256 }
1257 else {
1258 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
1259 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
1260 close();
1261 return;
1262 }
1263 }
1264 else {
1265 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
1266 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
1267 close();
1268 return;
1269 }
1270 }
1271 break;
1272
1273 case nmtSwitchSetupRequest:
1274 {
1275 //printf("Got nmtSwitchSetupRequest A gotIntro = %d\n",gotIntro);
1276 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtSwitchSetupRequest gotIntro = %d\n",__FILE__,__FUNCTION__,__LINE__,gotIntro);
1277
1278 if(gotIntro == true) {
1279 //printf("Got nmtSwitchSetupRequest B\n");
1280
1281 SwitchSetupRequest switchSetupRequest;
1282 if(receiveMessage(&switchSetupRequest)) {
1283 MutexSafeWrapper safeMutex(getServerSynchAccessor(),CODE_AT_LINE);
1284
1285 int slotIdx = switchSetupRequest.getCurrentSlotIndex();
1286 //int newSlotIdx = switchSetupRequest.getToSlotIndex();
1287 //printf("slotIdx = %d newSlotIdx = %d\n",slotIdx,newSlotIdx);
1288
1289 if(serverInterface->getSwitchSetupRequests(slotIdx) == NULL) {
1290 serverInterface->setSwitchSetupRequests(slotIdx,new SwitchSetupRequest());
1291 }
1292 *(serverInterface->getSwitchSetupRequests(slotIdx)) = switchSetupRequest;
1293
1294 //printf("slotIdx = %d newSlotIdx = %d\n",serverInterface->getSwitchSetupRequests(slotIdx)->getCurrentSlotIndex(),serverInterface->getSwitchSetupRequests(slotIdx)->getToSlotIndex());
1295
1296 this->playerStatus = switchSetupRequest.getNetworkPlayerStatus();
1297 this->name = switchSetupRequest.getNetworkPlayerName();
1298 this->playerLanguage = switchSetupRequest.getNetworkPlayerLanguage();
1299
1300 //printf("Got nmtSwitchSetupRequest C\n");
1301 //printf("In [%s::%s Line %d] networkPlayerName [%s]\n",__FILE__,__FUNCTION__,__LINE__,serverInterface->getSwitchSetupRequests()[factionIdx]->getNetworkPlayerName().c_str());
1302
1303 if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d] networkPlayerName [%s]\n",__FILE__,__FUNCTION__,__LINE__,serverInterface->getSwitchSetupRequests()[slotIdx]->getNetworkPlayerName().c_str());
1304 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] factionIdx = %d, switchSetupRequest.getNetworkPlayerName() [%s] switchSetupRequest.getNetworkPlayerStatus() = %d, switchSetupRequest.getSwitchFlags() = %d\n",__FILE__,__FUNCTION__,__LINE__,slotIdx,switchSetupRequest.getNetworkPlayerName().c_str(),switchSetupRequest.getNetworkPlayerStatus(),switchSetupRequest.getSwitchFlags());
1305 }
1306 else {
1307 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
1308 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
1309 close();
1310 return;
1311 }
1312 }
1313 else {
1314 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
1315 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
1316 close();
1317 return;
1318 }
1319
1320 break;
1321 }
1322
1323 case nmtReady:
1324 {
1325 NetworkMessageReady networkMessageReady;
1326 this->receiveMessage(&networkMessageReady);
1327
1328 // its simply ignored here. Probably we are starting a game
1329 //printf("Got ready message from client slot joinGameInProgress = %d\n",joinGameInProgress);
1330 if(joinGameInProgress == true) {
1331 NetworkMessageReady networkMessageReady(0);
1332 this->sendMessage(&networkMessageReady);
1333 this->setGameStarted(true);
1334
1335 this->currentFrameCount = serverInterface->getCurrentFrameCount();
1336 //printf("#2 Server slot got currentFrameCount = %d\n",currentFrameCount);
1337
1338 this->currentLagCount = 0;
1339 this->lastReceiveCommandListTime = time(NULL);
1340
1341 this->setReady();
1342 }
1343 // unpause the game
1344 else {
1345 this->setUnPauseForInGameConnection(true);
1346 }
1347 break;
1348 }
1349 case nmtLoadingStatusMessage:
1350 break;
1351
1352 default:
1353 {
1354 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] networkMessageType = %d\n",__FILE__,__FUNCTION__,__LINE__,networkMessageType);
1355
1356 if(gotIntro == true) {
1357 //throw megaglest_runtime_error("Unexpected message in connection slot: " + intToStr(networkMessageType));
1358 string sErr = "Unexpected message in connection slot: " + intToStr(networkMessageType);
1359 //sendTextMessage(sErr,-1);
1360 //DisplayErrorMessage(sErr);
1361 threadErrorList.push_back(sErr);
1362 return;
1363 }
1364 else {
1365 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got invalid message type before intro, disconnecting socket.\n",__FILE__,__FUNCTION__,__LINE__);
1366
1367 if(SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled) SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d]\nInvalid message type before intro handshake [%d]\nDisconnecting socket for slot: %d [%s].\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,networkMessageType,this->playerIndex,this->getIpAddress().c_str());
1368 this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress());
1369 close();
1370 return;
1371 }
1372 }
1373 }
1374
1375 //printf("#3 Server slot got currentFrameCount = %d\n",currentFrameCount);
1376
1377 // This may end up continuously lagging and not disconnecting players who have
1378 // just the 'wrong' amount of lag (but not enough to be horrible for a disconnect)
1379 if(Config::getInstance().getBool("AutoClientLagCorrection","true") == true) {
1380 double LAG_CHECK_GRACE_PERIOD = 15;
1381
1382 //printf("#4 Server slot got currentFrameCount = %d\n",currentFrameCount);
1383
1384 if(this->serverInterface->getGameStartTime() > 0 &&
1385 difftime((long int)time(NULL),this->serverInterface->getGameStartTime()) >= LAG_CHECK_GRACE_PERIOD &&
1386 difftime((long int)time(NULL),this->getConnectedTime()) >= LAG_CHECK_GRACE_PERIOD) {
1387 if(this->isConnected() == true && this->gotIntro == true && this->skipLagCheck == false) {
1388 double clientLag = this->serverInterface->getCurrentFrameCount() - this->getCurrentFrameCount();
1389 double clientLagCount = (gameSettings.getNetworkFramePeriod() > 0 ? (clientLag / gameSettings.getNetworkFramePeriod()) : 0);
1390 double clientLagTime = difftime((long int)time(NULL),this->getLastReceiveCommandListTime());
1391
1392 double maxFrameCountLagAllowed = 10;
1393 double maxClientLagTimeAllowed = 8;
1394
1395 // New lag check
1396 if((maxFrameCountLagAllowed > 0 && clientLagCount > maxFrameCountLagAllowed) ||
1397 (maxClientLagTimeAllowed > 0 && clientLagTime > maxClientLagTimeAllowed)) {
1398
1399 waitForLaggingClient = true;
1400 if(waitedForLaggingClient == false) {
1401 waitedForLaggingClient = true;
1402 printf("*TESTING*: START Waiting for lagging client playerIndex = %d [%s] clientLagCount = %f [%f]\n",playerIndex,name.c_str(),clientLagCount,clientLagTime);
1403 }
1404 }
1405 }
1406 }
1407
1408 //printf("#5 Server slot got currentFrameCount = %d\n",currentFrameCount);
1409 }
1410 //printf("#5a Server slot got currentFrameCount = %d\n",currentFrameCount);
1411 }
1412
1413 //printf("#6 Server slot got currentFrameCount = %d\n",currentFrameCount);
1414
1415 if(waitedForLaggingClient == true) {
1416 printf("*TESTING*: FINISHED Waiting for lagging client playerIndex = %d [%s]\n",playerIndex,name.c_str());
1417 }
1418
1419 //if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis());
1420
1421 validateConnection();
1422
1423 //printf("#7 Server slot got currentFrameCount = %d\n",currentFrameCount);
1424
1425 //if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis());
1426 }
1427 else {
1428 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] calling close...\n",__FILE__,__FUNCTION__,__LINE__);
1429
1430 //printf("Closing connection slot socketInfo.first = %d\n",socketInfo.first);
1431
1432 close();
1433
1434 //if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis());
1435 }
1436
1437 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1438 }
1439 }
1440 catch(const exception &ex) {
1441 SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
1442 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());
1443
1444 threadErrorList.push_back(ex.what());
1445
1446 //if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis());
1447 }
1448
1449 //printf("#8 Server slot got currentFrameCount = %d\n",currentFrameCount);
1450 //if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis());
1451 }
1452
validateConnection()1453 void ConnectionSlot::validateConnection() {
1454 if(this->isConnected() == true &&
1455 gotIntro == false && connectedTime > 0 &&
1456 difftime((long int)time(NULL),connectedTime) > GameConstants::maxClientConnectHandshakeSecs) {
1457
1458 //printf("Closing connection slot timed out!\n");
1459 close();
1460 }
1461 }
1462
resetJoinGameInProgressFlags()1463 void ConnectionSlot::resetJoinGameInProgressFlags() {
1464 this->gotIntro = false;
1465 this->skipLagCheck = false;
1466 this->joinGameInProgress = false;
1467 this->ready = false;
1468 }
1469
setJoinGameInProgressFlags()1470 void ConnectionSlot::setJoinGameInProgressFlags() {
1471 this->gotIntro = true;
1472 this->skipLagCheck = true;
1473 this->joinGameInProgress = true;
1474 this->ready = false;
1475 this->sentSavedGameInfo = false;
1476 }
1477
close()1478 void ConnectionSlot::close() {
1479 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s LINE: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1480
1481 //printf("Closing slot for playerIndex = %d\n",playerIndex);
1482 //if(serverInterface->getAllowInGameConnections() == true) {
1483 //printf("Closing connection slot!\n");
1484 //}
1485 //printf("ConnectionSlot::close() #1 this->getSocket() = %p\n",this->getSocket());
1486
1487 this->gotIntro = false;
1488 this->skipLagCheck = false;
1489 this->joinGameInProgress = false;
1490 this->sentSavedGameInfo = false;
1491 this->pauseForInGameConnection = false;
1492 this->unPauseForInGameConnection = false;
1493 this->ready = false;
1494 this->connectedTime = 0;
1495
1496 if(this->slotThreadWorker != NULL) {
1497 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1498 this->slotThreadWorker->setAllEventsCompleted();
1499 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1500 }
1501
1502 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1503
1504 //printf("ConnectionSlot::close() #2 this->getSocket() = %p\n",this->getSocket());
1505
1506 MutexSafeWrapper safeMutex(mutexCloseConnection,CODE_AT_LINE);
1507 bool updateServerListener = (this->getSocket() != NULL);
1508
1509 //printf("ConnectionSlot::close() #3 this->getSocket() = %p updateServerListener = %d\n",this->getSocket(),updateServerListener);
1510
1511 this->deleteSocket();
1512 safeMutex.ReleaseLock();
1513
1514 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s LINE: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1515 //printf("Closing slot for playerIndex = %d updateServerListener = %d ready = %d\n",playerIndex,updateServerListener,ready);
1516
1517 if(updateServerListener == true) {
1518 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s LINE: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1519 serverInterface->updateListen();
1520 }
1521
1522 if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END\n",__FILE__,__FUNCTION__);
1523 }
1524
getServerSynchAccessor()1525 Mutex * ConnectionSlot::getServerSynchAccessor() {
1526 return (serverInterface != NULL ? serverInterface->getServerSynchAccessor() : NULL);
1527 }
1528
signalUpdate(ConnectionSlotEvent * event)1529 void ConnectionSlot::signalUpdate(ConnectionSlotEvent *event) {
1530 if(slotThreadWorker != NULL) {
1531 slotThreadWorker->signalUpdate(event);
1532 }
1533 }
1534
updateCompleted(ConnectionSlotEvent * event)1535 bool ConnectionSlot::updateCompleted(ConnectionSlotEvent *event) {
1536 bool waitingForThread = (slotThreadWorker != NULL &&
1537 slotThreadWorker->isSignalCompleted(event) == false &&
1538 slotThreadWorker->getQuitStatus() == false &&
1539 slotThreadWorker->getRunningStatus() == true);
1540
1541 return (waitingForThread == false);
1542 }
1543
sendMessage(NetworkMessage * networkMessage)1544 void ConnectionSlot::sendMessage(NetworkMessage* networkMessage) {
1545 MutexSafeWrapper safeMutex(socketSynchAccessor,CODE_AT_LINE);
1546
1547 // Skip text messages not intended for the players preferred language
1548 NetworkMessageText *textMsg = dynamic_cast<NetworkMessageText *>(networkMessage);
1549 if(textMsg != NULL) {
1550 //printf("\n\n\n~~~ SERVER HAS NetworkMessageText target [%s] player [%s] msg[%s]\n\n\n",textMsg->getTargetLanguage().c_str(),this->getNetworkPlayerLanguage().c_str(), textMsg->getText().c_str());
1551 if(textMsg->getTargetLanguage() != "" &&
1552 textMsg->getTargetLanguage() != this->getNetworkPlayerLanguage()) {
1553 return;
1554 }
1555 }
1556
1557 NetworkInterface::sendMessage(networkMessage);
1558 }
1559
getHumanPlayerName(int index)1560 string ConnectionSlot::getHumanPlayerName(int index) {
1561 return serverInterface->getHumanPlayerName(index);
1562 }
1563
getPendingNetworkCommandList(bool clearList)1564 vector<NetworkCommand> ConnectionSlot::getPendingNetworkCommandList(bool clearList) {
1565 vector<NetworkCommand> ret;
1566 MutexSafeWrapper safeMutexSlot(mutexPendingNetworkCommandList,CODE_AT_LINE);
1567 if(vctPendingNetworkCommandList.empty() == false) {
1568 ret = vctPendingNetworkCommandList;
1569 if(clearList == true) {
1570 vctPendingNetworkCommandList.clear();
1571 }
1572 }
1573
1574 return ret;
1575 }
1576
clearPendingNetworkCommandList()1577 void ConnectionSlot::clearPendingNetworkCommandList() {
1578 MutexSafeWrapper safeMutexSlot(mutexPendingNetworkCommandList,CODE_AT_LINE);
1579 if(vctPendingNetworkCommandList.empty() == false) {
1580 vctPendingNetworkCommandList.clear();
1581 }
1582 }
1583
hasValidSocketId()1584 bool ConnectionSlot::hasValidSocketId() {
1585 bool result = false;
1586 MutexSafeWrapper safeMutexSlot(mutexSocket,CODE_AT_LINE);
1587 if(socket != NULL && socket->getSocketId() > 0) {
1588 result = true;
1589 }
1590 return result;
1591
1592 }
1593
isConnected()1594 bool ConnectionSlot::isConnected() {
1595 bool result = false;
1596 MutexSafeWrapper safeMutexSlot(mutexSocket,CODE_AT_LINE);
1597 if(socket != NULL && socket->isConnected() == true) {
1598 result = true;
1599 }
1600 return result;
1601 }
1602
getSocketId()1603 PLATFORM_SOCKET ConnectionSlot::getSocketId() {
1604 PLATFORM_SOCKET result = 0;
1605 MutexSafeWrapper safeMutexSlot(mutexSocket,CODE_AT_LINE);
1606 if(socket != NULL) {
1607 result = socket->getSocketId();
1608 }
1609 return result;
1610 }
1611
getSocketInfo()1612 pair<bool,Socket*> ConnectionSlot::getSocketInfo() {
1613 pair<bool,Socket*> result;
1614 MutexSafeWrapper safeMutexSlot(mutexSocket,CODE_AT_LINE);
1615 result.first = (socket != NULL && socket->isConnected());
1616 result.second = socket;
1617
1618 return result;
1619
1620 }
1621
getSocket(bool mutexLock)1622 Socket* ConnectionSlot::getSocket(bool mutexLock) {
1623 MutexSafeWrapper safeMutexSlot(NULL,CODE_AT_LINE);
1624 if(mutexLock == true) {
1625 safeMutexSlot.setMutex(mutexSocket,CODE_AT_LINE);
1626 }
1627 return socket;
1628 }
1629
setSocket(Socket * newSocket)1630 void ConnectionSlot::setSocket(Socket *newSocket) {
1631 MutexSafeWrapper safeMutexSlot(mutexSocket,CODE_AT_LINE);
1632 socket = newSocket;
1633 }
1634
deleteSocket()1635 void ConnectionSlot::deleteSocket() {
1636 MutexSafeWrapper safeMutexSlot(mutexSocket,CODE_AT_LINE);
1637 delete socket;
1638 socket = NULL;
1639 }
1640
hasDataToRead()1641 bool ConnectionSlot::hasDataToRead() {
1642 bool result = false;
1643
1644 MutexSafeWrapper safeMutexSlot(mutexSocket,CODE_AT_LINE);
1645 if(socket != NULL && socket->hasDataToRead() == true) {
1646 result = true;
1647 }
1648
1649 return result;
1650 }
1651
1652 }}//end namespace
1653