Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1652 lines (1365 sloc)
79.6 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ============================================================== | |
| // This file is part of Glest (www.glest.org) | |
| // | |
| // Copyright (C) 2001-2008 Martiño Figueroa | |
| // | |
| // You can redistribute this code and/or modify it under | |
| // the terms of the GNU General Public License as published | |
| // by the Free Software Foundation; either version 2 of the | |
| // License, or (at your option) any later version | |
| // ============================================================== | |
| #include "connection_slot.h" | |
| #include "conversion.h" | |
| #include "game_util.h" | |
| #include "config.h" | |
| #include "server_interface.h" | |
| #include "network_message.h" | |
| #include "platform_util.h" | |
| #include <stdexcept> | |
| #include "leak_dumper.h" | |
| using namespace std; | |
| using namespace Shared::Util; | |
| namespace Glest{ namespace Game{ | |
| // ===================================================== | |
| // class ConnectionSlotThread | |
| // ===================================================== | |
| ConnectionSlotThread::ConnectionSlotThread(int slotIndex) : BaseThread() { | |
| this->masterController = NULL; | |
| this->triggerIdMutex = new Mutex(CODE_AT_LINE); | |
| this->slotIndex = slotIndex; | |
| this->slotInterface = NULL; | |
| uniqueID = "ConnectionSlotThread"; | |
| eventList.clear(); | |
| eventList.reserve(1000); | |
| triggerGameStarted = new Mutex(CODE_AT_LINE); | |
| gameStarted = false; | |
| } | |
| ConnectionSlotThread::ConnectionSlotThread(ConnectionSlotCallbackInterface *slotInterface,int slotIndex) : BaseThread() { | |
| this->masterController = NULL; | |
| this->triggerIdMutex = new Mutex(CODE_AT_LINE); | |
| this->slotIndex = slotIndex; | |
| this->slotInterface = slotInterface; | |
| uniqueID = "ConnectionSlotThread"; | |
| eventList.clear(); | |
| triggerGameStarted = new Mutex(CODE_AT_LINE); | |
| gameStarted = false; | |
| } | |
| ConnectionSlotThread::~ConnectionSlotThread() { | |
| delete triggerIdMutex; | |
| triggerIdMutex = NULL; | |
| delete triggerGameStarted; | |
| triggerGameStarted = NULL; | |
| } | |
| void ConnectionSlotThread::setQuitStatus(bool value) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d value = %d\n",__FILE__,__FUNCTION__,__LINE__,value); | |
| BaseThread::setQuitStatus(value); | |
| if(value == true) { | |
| signalUpdate(NULL); | |
| } | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); | |
| } | |
| void ConnectionSlotThread::signalUpdate(ConnectionSlotEvent *event) { | |
| if(event != NULL) { | |
| MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE); | |
| eventList.push_back(*event); | |
| } | |
| if(getGameStarted() == true && getQuitStatus() == true) { | |
| return; | |
| } | |
| semTaskSignalled.signal(); | |
| } | |
| void ConnectionSlotThread::setTaskCompleted(int eventId) { | |
| if(eventId > 0) { | |
| MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE); | |
| for(int index = 0; index < (int)eventList.size(); ++index) { | |
| ConnectionSlotEvent &slotEvent = eventList[index]; | |
| if(slotEvent.eventId == eventId) { | |
| slotEvent.eventCompleted = true; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| //void ConnectionSlotThread::purgeAllEvents() { | |
| // MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE); | |
| // eventList.clear(); | |
| //} | |
| void ConnectionSlotThread::setAllEventsCompleted() { | |
| MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE); | |
| for(int index = 0; index < (int)eventList.size(); ++index) { | |
| ConnectionSlotEvent &slotEvent = eventList[index]; | |
| if(slotEvent.eventCompleted == false) { | |
| slotEvent.eventCompleted = true; | |
| } | |
| } | |
| } | |
| void ConnectionSlotThread::purgeCompletedEvents() { | |
| MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE); | |
| for(int index = (int)eventList.size() - 1; index >= 0; index--) { | |
| ConnectionSlotEvent &slotEvent = eventList[index]; | |
| if(slotEvent.eventCompleted == true) { | |
| eventList.erase(eventList.begin() + index); | |
| } | |
| } | |
| } | |
| bool ConnectionSlotThread::canShutdown(bool deleteSelfIfShutdownDelayed) { | |
| bool ret = (getExecutingTask() == false); | |
| if(ret == false && deleteSelfIfShutdownDelayed == true) { | |
| setDeleteSelfOnExecutionDone(deleteSelfIfShutdownDelayed); | |
| deleteSelfIfRequired(); | |
| signalQuit(); | |
| } | |
| return ret; | |
| } | |
| bool ConnectionSlotThread::isSignalCompleted(ConnectionSlotEvent *event) { | |
| bool result = false; | |
| if(event != NULL) { | |
| MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE); | |
| for(int index = 0; index < (int)eventList.size(); ++index) { | |
| ConnectionSlotEvent &slotEvent = eventList[index]; | |
| if(slotEvent.eventId == event->eventId) { | |
| result = slotEvent.eventCompleted; | |
| break; | |
| } | |
| } | |
| } | |
| return result; | |
| } | |
| void ConnectionSlotThread::slotUpdateTask(ConnectionSlotEvent *event) { | |
| if(event != NULL && event->connectionSlot != NULL) { | |
| if(event->eventType == eSendSocketData) { | |
| event->connectionSlot->sendMessage(event->networkMessage); | |
| } | |
| else if(event->eventType == eReceiveSocketData) { | |
| event->connectionSlot->updateSlot(event); | |
| } | |
| } | |
| } | |
| void ConnectionSlotThread::signalSlave(void *userdata) { | |
| std::map<int,ConnectionSlotEvent> *eventList = (std::map<int,ConnectionSlotEvent> *)userdata; | |
| ConnectionSlotEvent &event = (*eventList)[slotIndex]; | |
| signalUpdate(&event); | |
| } | |
| bool ConnectionSlotThread::getGameStarted() { | |
| MutexSafeWrapper safeMutexGameStarted(triggerGameStarted,CODE_AT_LINE); | |
| return gameStarted; | |
| } | |
| void ConnectionSlotThread::setGameStarted(bool value) { | |
| MutexSafeWrapper safeMutexGameStarted(triggerGameStarted,CODE_AT_LINE); | |
| if(gameStarted != value) { | |
| gameStarted = value; | |
| if(gameStarted == true) { | |
| semTaskSignalled.signal(); | |
| } | |
| } | |
| } | |
| void ConnectionSlotThread::execute() { | |
| RunningStatusSafeWrapper runningStatus(this); | |
| try { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| //printf("Starting client SLOT thread: %d\n",slotIndex); | |
| for(;this->slotInterface != NULL;) { | |
| if(getQuitStatus() == true) { | |
| SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| break; | |
| } | |
| // Does this game allow joining in progress play and is this slot | |
| // not already connected to a client? | |
| if( this->slotInterface->getAllowInGameConnections() == true && | |
| this->slotInterface->isClientConnected(slotIndex) == false) { | |
| //printf("#1 Non connected slot: %d waiting for client connection..\n",slotIndex); | |
| sleep(100); | |
| if(getQuitStatus() == true) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| break; | |
| } | |
| //printf("Slot thread slotIndex: %d eventCount: %d\n",slotIndex,eventCount); | |
| ConnectionSlotEvent eventCopy; | |
| eventCopy.eventType = eReceiveSocketData; | |
| eventCopy.connectionSlot = this->slotInterface->getSlot(slotIndex,true); | |
| if(getQuitStatus() == true) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| break; | |
| } | |
| ExecutingTaskSafeWrapper safeExecutingTaskMutex(this); | |
| this->slotUpdateTask(&eventCopy); | |
| } | |
| else { | |
| // If the game already started? | |
| if(getGameStarted() == true) { | |
| //printf("#A Checking action for slot: %d\n",slotIndex); | |
| if(getQuitStatus() == true) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| break; | |
| } | |
| ExecutingTaskSafeWrapper safeExecutingTaskMutex(this); | |
| // If the slot or socket are NULL the connection was lost | |
| // so exit the thread | |
| MutexSafeWrapper safeMutex(this->slotInterface->getSlotMutex(slotIndex),CODE_AT_LINE); | |
| ConnectionSlot *slot = this->slotInterface->getSlot(slotIndex,false); | |
| if(slot == NULL) { | |
| break; | |
| } | |
| Socket *socket = slot->getSocket(true); | |
| if(socket == NULL) { | |
| break; | |
| } | |
| PLATFORM_SOCKET socketId = socket->getSocketId(); | |
| safeMutex.ReleaseLock(); | |
| // Avoid mutex locking | |
| //bool socketHasReadData = Socket::hasDataToRead(socket->getSocketId()); | |
| bool socketHasReadData = Socket::hasDataToReadWithWait(socketId,150000); | |
| if(getQuitStatus() == true) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| break; | |
| } | |
| ConnectionSlotEvent eventCopy; | |
| eventCopy.eventType = eReceiveSocketData; | |
| eventCopy.connectionSlot = this->slotInterface->getSlot(slotIndex,true); | |
| eventCopy.eventId = slotIndex; | |
| eventCopy.socketTriggered = socketHasReadData; | |
| if(getQuitStatus() == true) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| break; | |
| } | |
| this->slotUpdateTask(&eventCopy); | |
| } | |
| // Game has not yet started | |
| else { | |
| //printf("#1 Checking action for slot: %d\n",slotIndex); | |
| if(getGameStarted() == true) { | |
| continue; | |
| } | |
| //printf("#2 Checking action for slot: %d\n",slotIndex); | |
| semTaskSignalled.waitTillSignalled(); | |
| //printf("#3 Checking action for slot: %d\n",slotIndex); | |
| if(getGameStarted() == true) { | |
| continue; | |
| } | |
| //printf("#4 Checking action for slot: %d\n",slotIndex); | |
| static string masterSlaveOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); | |
| MasterSlaveThreadControllerSafeWrapper safeMasterController(masterController,20000,masterSlaveOwnerId); | |
| if(getQuitStatus() == true) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| break; | |
| } | |
| MutexSafeWrapper safeMutex(triggerIdMutex,CODE_AT_LINE); | |
| int eventCount = (int)eventList.size(); | |
| //printf("Slot thread slotIndex: %d eventCount: %d\n",slotIndex,eventCount); | |
| 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); | |
| if(eventCount > 0) { | |
| ConnectionSlotEvent eventCopy; | |
| for(int i = 0; i < (int)eventList.size(); ++i) { | |
| ConnectionSlotEvent &slotEvent = eventList[i]; | |
| if(slotEvent.eventCompleted == false) { | |
| eventCopy = slotEvent; | |
| break; | |
| } | |
| } | |
| safeMutex.ReleaseLock(); | |
| if(getQuitStatus() == true) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| break; | |
| } | |
| if(eventCopy.eventId > 0) { | |
| ExecutingTaskSafeWrapper safeExecutingTaskMutex(this); | |
| 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); | |
| //printf("#1 Slot thread slotIndex: %d eventCount: %d eventCopy.eventId: %d\n",slotIndex,eventCount,(int)eventCopy.eventId); | |
| this->slotUpdateTask(&eventCopy); | |
| setTaskCompleted(eventCopy.eventId); | |
| //printf("#2 Slot thread slotIndex: %d eventCount: %d eventCopy.eventId: %d\n",slotIndex,eventCount,(int)eventCopy.eventId); | |
| } | |
| } | |
| } | |
| } | |
| if(getQuitStatus() == true) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| break; | |
| } | |
| } | |
| //printf("Ending client SLOT thread: %d\n",slotIndex); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| } | |
| catch(const exception &ex) { | |
| SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| throw megaglest_runtime_error(ex.what()); | |
| } | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); | |
| } | |
| // ===================================================== | |
| // class ConnectionSlot | |
| // ===================================================== | |
| ConnectionSlot::ConnectionSlot(ServerInterface* serverInterface, int playerIndex) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); | |
| this->mutexSocket = new Mutex(CODE_AT_LINE); | |
| this->socket = NULL; | |
| this->mutexCloseConnection = new Mutex(CODE_AT_LINE); | |
| this->mutexPendingNetworkCommandList = new Mutex(CODE_AT_LINE); | |
| this->socketSynchAccessor = new Mutex(CODE_AT_LINE); | |
| this->connectedRemoteIPAddress = 0; | |
| this->sessionKey = 0; | |
| this->serverInterface = serverInterface; | |
| this->playerIndex = playerIndex; | |
| this->playerStatus = npst_None; | |
| this->playerLanguage = ""; | |
| this->playerUUID = ""; | |
| this->platform = ""; | |
| this->currentFrameCount = 0; | |
| this->currentLagCount = 0; | |
| this->gotLagCountWarning = false; | |
| this->lastReceiveCommandListTime = 0; | |
| this->receivedNetworkGameStatus = false; | |
| this->autoPauseGameCountForLag = 0; | |
| this->skipLagCheck = false; | |
| this->joinGameInProgress = false; | |
| this->canAcceptConnections = true; | |
| this->startInGameConnectionLaunch = false; | |
| this->pauseForInGameConnection = false; | |
| this->unPauseForInGameConnection = false; | |
| this->sentSavedGameInfo = false; | |
| this->ready = false; | |
| this->gotIntro = false; | |
| this->connectedTime = 0; | |
| this->networkGameDataSynchCheckOkMap = false; | |
| this->networkGameDataSynchCheckOkTile = false; | |
| this->networkGameDataSynchCheckOkTech = false; | |
| this->setNetworkGameDataSynchCheckTechMismatchReport(""); | |
| this->setReceivedDataSynchCheck(false); | |
| this->clearChatInfo(); | |
| this->setSocket(NULL); | |
| this->slotThreadWorker = NULL; | |
| static string mutexOwnerId = string(extractFileFromDirectoryPath(__FILE__).c_str()) + string("_") + intToStr(__LINE__); | |
| this->slotThreadWorker = new ConnectionSlotThread(this->serverInterface,playerIndex); | |
| this->slotThreadWorker->setUniqueID(mutexOwnerId); | |
| this->slotThreadWorker->start(); | |
| } | |
| ConnectionSlot::~ConnectionSlot() { | |
| //printf("===> Destructor for ConnectionSlot = %d\n",playerIndex); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] START\n",__FILE__,__FUNCTION__,__LINE__); | |
| //printf("Deleting connection slot\n"); | |
| close(); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| //printf("#1 Ending client SLOT: %d slotThreadWorker: %p\n",playerIndex,slotThreadWorker); | |
| if(slotThreadWorker != NULL) { | |
| slotThreadWorker->signalQuit(); | |
| } | |
| if( slotThreadWorker != NULL && | |
| slotThreadWorker->canShutdown(false) == true && | |
| slotThreadWorker->getRunningStatus() == false) { | |
| //printf("#2 Ending client SLOT: %d\n",playerIndex); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| delete slotThreadWorker; | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| } | |
| else if(slotThreadWorker != NULL && | |
| slotThreadWorker->canShutdown(true) == true) { | |
| if(slotThreadWorker->getRunningStatus() == false) { | |
| //printf("#3 Ending client SLOT: %d\n",playerIndex); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| delete slotThreadWorker; | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| } | |
| else { | |
| slotThreadWorker->setDeleteSelfOnExecutionDone(true); | |
| slotThreadWorker->setDeleteAfterExecute(true); | |
| } | |
| } | |
| //printf("#4 Ending client SLOT: %d\n",playerIndex); | |
| slotThreadWorker = NULL; | |
| delete socketSynchAccessor; | |
| socketSynchAccessor = NULL; | |
| delete mutexPendingNetworkCommandList; | |
| mutexPendingNetworkCommandList = NULL; | |
| delete mutexCloseConnection; | |
| mutexCloseConnection = NULL; | |
| delete mutexSocket; | |
| mutexSocket = NULL; | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END\n",__FILE__,__FUNCTION__); | |
| } | |
| int ConnectionSlot::getAutoPauseGameCountForLag() { | |
| return autoPauseGameCountForLag; | |
| } | |
| void ConnectionSlot::incrementAutoPauseGameCountForLag() { | |
| autoPauseGameCountForLag++; | |
| } | |
| bool ConnectionSlot::getGameStarted() { | |
| bool result = false; | |
| if(this->slotThreadWorker != NULL) { | |
| result = this->slotThreadWorker->getGameStarted(); | |
| } | |
| return result; | |
| } | |
| void ConnectionSlot::setGameStarted(bool value) { | |
| if(this->slotThreadWorker != NULL) { | |
| this->slotThreadWorker->setGameStarted(value); | |
| } | |
| } | |
| void ConnectionSlot::setPlayerIndex(int value) { | |
| playerIndex = value; | |
| if(this->slotThreadWorker != NULL) { | |
| this->slotThreadWorker->setSlotIndex(playerIndex); | |
| } | |
| } | |
| void ConnectionSlot::setReady() { | |
| this->ready= true; | |
| this->skipLagCheck = false; | |
| this->joinGameInProgress = false; | |
| this->sentSavedGameInfo = false; | |
| } | |
| void ConnectionSlot::updateSlot(ConnectionSlotEvent *event) { | |
| if(event != NULL) { | |
| bool &socketTriggered = event->socketTriggered; | |
| bool checkForNewClients = | |
| (serverInterface->getGameHasBeenInitiated() == false || | |
| serverInterface->getAllowInGameConnections() == true); | |
| //if((serverInterface->getGameHasBeenInitiated() == false || | |
| // (serverInterface->getAllowInGameConnections() == true && this->isConnected() == false) || | |
| // socketTriggered == true)) { | |
| if(socketTriggered == true || | |
| ((serverInterface->getGameHasBeenInitiated() == false || | |
| serverInterface->getAllowInGameConnections() == true) && | |
| this->isConnected() == false)) { | |
| this->update(checkForNewClients,event->triggerId); | |
| } | |
| //} | |
| } | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| } | |
| string ConnectionSlot::getIpAddress(bool mutexLock) { | |
| string result = ""; | |
| MutexSafeWrapper safeMutexSlot((mutexLock == true ? mutexSocket : NULL),CODE_AT_LINE); | |
| if(socket != NULL) { | |
| result = socket->getIpAddress(); | |
| } | |
| return result; | |
| } | |
| void ConnectionSlot::update(bool checkForNewClients,int lockedSlotIndex) { | |
| try { | |
| clearThreadErrorList(); | |
| if(slotThreadWorker != NULL) { | |
| slotThreadWorker->purgeCompletedEvents(); | |
| } | |
| pair<bool,Socket*> socketInfo = this->getSocketInfo(); | |
| if(socketInfo.second == NULL) { | |
| if(networkGameDataSynchCheckOkMap) networkGameDataSynchCheckOkMap = false; | |
| if(networkGameDataSynchCheckOkTile) networkGameDataSynchCheckOkTile = false; | |
| if(networkGameDataSynchCheckOkTech) networkGameDataSynchCheckOkTech = false; | |
| this->setReceivedDataSynchCheck(false); | |
| // Is the listener socket ready to be read? | |
| if(checkForNewClients == true && this->canAcceptConnections == true) { | |
| 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()); | |
| //printf("Checking for new connections...\n"); | |
| bool hasData = (serverInterface->getServerSocket() != NULL && | |
| serverInterface->getServerSocket()->hasDataToRead() == true); | |
| //printf("Server socket hasData: %d\n",hasData); | |
| if(hasData == true) { | |
| 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); | |
| Socket *newSocket = serverInterface->getServerSocket()->accept(false); | |
| //printf("Server socket newSocket: %p\n",newSocket); | |
| 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); | |
| if(newSocket != NULL) { | |
| // Set Socket as non-blocking | |
| newSocket->setBlock(false); | |
| MutexSafeWrapper safeMutex(mutexCloseConnection,CODE_AT_LINE); | |
| this->setSocket(newSocket); | |
| safeMutex.ReleaseLock(); | |
| this->connectedTime = time(NULL); | |
| this->clearChatInfo(); | |
| this->name = ""; | |
| this->playerStatus = npst_PickSettings; | |
| this->playerLanguage = ""; | |
| this->playerUUID = ""; | |
| this->platform = ""; | |
| this->ready = false; | |
| this->vctFileList.clear(); | |
| this->receivedNetworkGameStatus = false; | |
| this->gotIntro = false; | |
| MutexSafeWrapper safeMutexSlot1(mutexPendingNetworkCommandList,CODE_AT_LINE); | |
| this->vctPendingNetworkCommandList.clear(); | |
| safeMutexSlot1.ReleaseLock(); | |
| this->currentFrameCount = 0; | |
| this->currentLagCount = 0; | |
| this->lastReceiveCommandListTime = 0; | |
| this->gotLagCountWarning = false; | |
| this->versionString = ""; | |
| serverInterface->updateListen(); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] playerIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,playerIndex); | |
| } | |
| else { | |
| close(); | |
| return; | |
| } | |
| //send intro message when connected | |
| if(this->isConnected() == true) { | |
| //printf("Server socket newSocket is connected: %d\n",playerIndex); | |
| Chrono seed(true); | |
| srand((unsigned int)seed.getCurTicks() / (this->playerIndex + 1)); | |
| sessionKey = rand() % 1000000; | |
| 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); | |
| 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__); | |
| NetworkMessageIntro networkMessageIntro( | |
| sessionKey, | |
| getNetworkVersionGITString(), | |
| getHostName(), | |
| playerIndex, | |
| nmgstOk, | |
| 0, | |
| ServerSocket::getFTPServerPort(), | |
| "", | |
| serverInterface->getGameHasBeenInitiated(), | |
| Config::getInstance().getString("PlayerId",""), | |
| getPlatformNameString()); | |
| sendMessage(&networkMessageIntro); | |
| if(this->serverInterface->getGameHasBeenInitiated() == true) { | |
| setGameStarted(true); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| else { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| if(socketInfo.first == true) { | |
| this->clearChatInfo(); | |
| bool gotTextMsg = true; | |
| bool gotCellMarkerMsg = true; | |
| bool waitForLaggingClient = false; | |
| bool waitedForLaggingClient = false; | |
| //printf("Update slot: %d this->hasDataToRead(): %d\n",this->playerIndex,this->hasDataToRead()); | |
| for(;waitForLaggingClient == true || | |
| (this->hasDataToRead() == true && | |
| (gotTextMsg == true || gotCellMarkerMsg == true));) { | |
| //printf("Server slot checking for waitForLaggingClient = %d this->hasDataToRead() = %d gotTextMsg = %d gotCellMarkerMsg = %d\n",waitForLaggingClient,this->hasDataToRead(),gotTextMsg,gotCellMarkerMsg); | |
| waitForLaggingClient = false; | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] polling for networkMessageType...\n",__FILE__,__FUNCTION__,__LINE__); | |
| NetworkMessageType networkMessageType= getNextMessageType(); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] networkMessageType = %d\n",__FILE__,__FUNCTION__,__LINE__,networkMessageType); | |
| gotTextMsg = false; | |
| gotCellMarkerMsg = false; | |
| //process incoming commands | |
| switch(networkMessageType) { | |
| case nmtInvalid: | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtInvalid\n",__FILE__,__FUNCTION__,__LINE__); | |
| break; | |
| case nmtPing: | |
| { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtPing\n",__FILE__,__FUNCTION__); | |
| // client REQUIRES a ping before completing intro | |
| // authentication | |
| NetworkMessagePing networkMessagePing; | |
| if(receiveMessage(&networkMessagePing)) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| lastPingInfo = networkMessagePing; | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| break; | |
| case nmtText: | |
| { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtText gotIntro = %d\n",__FILE__,__FUNCTION__,__LINE__,gotIntro); | |
| if(gotIntro == true) { | |
| NetworkMessageText networkMessageText; | |
| if(receiveMessage(&networkMessageText)) { | |
| ChatMsgInfo msg(networkMessageText.getText().c_str(),networkMessageText.getTeamIndex(),networkMessageText.getPlayerIndex(),networkMessageText.getTargetLanguage()); | |
| this->addChatInfo(msg); | |
| gotTextMsg = true; | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| break; | |
| case nmtMarkCell: | |
| { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtMarkCell gotIntro = %d\n",__FILE__,__FUNCTION__,__LINE__,gotIntro); | |
| if(gotIntro == true) { | |
| NetworkMessageMarkCell networkMessageMarkCell; | |
| if(receiveMessage(&networkMessageMarkCell)) { | |
| MarkedCell msg(networkMessageMarkCell.getTarget(), | |
| networkMessageMarkCell.getFactionIndex(), | |
| networkMessageMarkCell.getText().c_str(), | |
| networkMessageMarkCell.getPlayerIndex()); | |
| this->addMarkedCell(msg); | |
| gotCellMarkerMsg = true; | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| break; | |
| case nmtUnMarkCell: | |
| { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtUnMarkCell gotIntro = %d\n",__FILE__,__FUNCTION__,__LINE__,gotIntro); | |
| if(gotIntro == true) { | |
| NetworkMessageUnMarkCell networkMessageMarkCell; | |
| if(receiveMessage(&networkMessageMarkCell)) { | |
| UnMarkedCell msg(networkMessageMarkCell.getTarget(), | |
| networkMessageMarkCell.getFactionIndex()); | |
| this->addUnMarkedCell(msg); | |
| gotCellMarkerMsg = true; | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| break; | |
| case nmtHighlightCell: | |
| { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtMarkCell gotIntro = %d\n",__FILE__,__FUNCTION__,__LINE__,gotIntro); | |
| if(gotIntro == true) { | |
| NetworkMessageHighlightCell networkMessageHighlightCell; | |
| if(receiveMessage(&networkMessageHighlightCell)) { | |
| MarkedCell msg(networkMessageHighlightCell.getTarget(), | |
| networkMessageHighlightCell.getFactionIndex(),"none",-1); | |
| this->setHighlightedCell(msg); | |
| gotCellMarkerMsg = true; | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| break; | |
| //command list | |
| case nmtCommandList: { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtCommandList gotIntro = %d\n",__FILE__,__FUNCTION__,__LINE__,gotIntro); | |
| if(gotIntro == true) { | |
| NetworkMessageCommandList networkMessageCommandList; | |
| if(receiveMessage(&networkMessageCommandList)) { | |
| currentFrameCount = networkMessageCommandList.getFrameCount(); | |
| lastReceiveCommandListTime = time(NULL); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] currentFrameCount = %d\n",__FILE__,__FUNCTION__,__LINE__,currentFrameCount); | |
| MutexSafeWrapper safeMutexSlot(mutexPendingNetworkCommandList,CODE_AT_LINE); | |
| for(int i = 0; i < networkMessageCommandList.getCommandCount(); ++i) { | |
| vctPendingNetworkCommandList.push_back(*networkMessageCommandList.getCommand(i)); | |
| } | |
| //printf("Got commands from client frame: %d count: %d\n",currentFrameCount,vctPendingNetworkCommandList.size()); | |
| //printf("#2 Server slot got currentFrameCount = %d\n",currentFrameCount); | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| break; | |
| //process intro messages | |
| case nmtIntro: | |
| { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtIntro\n",__FILE__,__FUNCTION__); | |
| NetworkMessageIntro networkMessageIntro; | |
| if(receiveMessage(&networkMessageIntro)) { | |
| int32 msgSessionId = networkMessageIntro.getSessionId(); | |
| this->name= networkMessageIntro.getName(); | |
| this->versionString = networkMessageIntro.getVersionString(); | |
| this->connectedRemoteIPAddress = networkMessageIntro.getExternalIp(); | |
| this->playerLanguage = networkMessageIntro.getPlayerLanguage(); | |
| this->playerUUID = networkMessageIntro.getPlayerUUID(); | |
| this->platform = networkMessageIntro.getPlayerPlatform(); | |
| //printf("Got uuid from client [%s]\n",this->playerUUID.c_str()); | |
| 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); | |
| if(msgSessionId != sessionKey) { | |
| string playerNameStr = name; | |
| string sErr = "Client gave invalid sessionid for player [" + playerNameStr + "] actual [" + intToStr(msgSessionId) + "] expected [" + intToStr(sessionKey) + "]"; | |
| printf("%s\n",sErr.c_str()); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str()); | |
| close(); | |
| return; | |
| } | |
| else if(this->playerUUID == "") { | |
| string playerNameStr = name; | |
| string sErr = "Client gave an invalid UUID for player [" + playerNameStr + "]"; | |
| printf("%s\n",sErr.c_str()); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str()); | |
| close(); | |
| return; | |
| } | |
| else { | |
| //check consistency | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| bool compatible = checkVersionComptability(getNetworkVersionGITString(), networkMessageIntro.getVersionString()); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| if(compatible == false) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| bool versionMatched = false; | |
| string platformFreeVersion = getNetworkPlatformFreeVersionString(); | |
| string sErr = ""; | |
| if(strncmp(platformFreeVersion.c_str(),networkMessageIntro.getVersionString().c_str(),strlen(platformFreeVersion.c_str())) != 0) { | |
| string playerNameStr = name; | |
| sErr = "Server and client binary mismatch!\nYou have to use the exactly same binaries!\n\nServer: " + getNetworkVersionGITString() + | |
| "\nClient: " + networkMessageIntro.getVersionString() + " player [" + playerNameStr + "]"; | |
| printf("%s\n",sErr.c_str()); | |
| serverInterface->sendTextMessage("Server and client binary mismatch!!",-1, true,"",lockedSlotIndex); | |
| serverInterface->sendTextMessage(" Server:" + getNetworkVersionGITString(),-1, true,"",lockedSlotIndex); | |
| serverInterface->sendTextMessage(" Client: "+ networkMessageIntro.getVersionString(),-1, true,"",lockedSlotIndex); | |
| serverInterface->sendTextMessage(" Client player [" + playerNameStr + "]",-1, true,"",lockedSlotIndex); | |
| } | |
| else { | |
| versionMatched = true; | |
| string playerNameStr = name; | |
| sErr = "Warning, Server and client are using the same version but different platforms.\n\nServer: " + getNetworkVersionGITString() + | |
| "\nClient: " + networkMessageIntro.getVersionString() + " player [" + playerNameStr + "]"; | |
| //printf("%s\n",sErr.c_str()); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str()); | |
| } | |
| if(Config::getInstance().getBool("PlatformConsistencyChecks","true") && | |
| versionMatched == false) { // error message and disconnect only if checked | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str()); | |
| close(); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str()); | |
| return; | |
| } | |
| } | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| gotIntro = true; | |
| int factionIndex = this->serverInterface->gameSettings.getFactionIndexForStartLocation(playerIndex); | |
| this->serverInterface->addClientToServerIPAddress(this->getSocket()->getConnectedIPAddress(this->getSocket()->getIpAddress()),this->connectedRemoteIPAddress); | |
| this->serverInterface->gameSettings.setNetworkPlayerUUID(factionIndex,this->playerUUID); | |
| this->serverInterface->gameSettings.setNetworkPlayerPlatform(factionIndex,this->platform); | |
| if(serverInterface->getGameHasBeenInitiated() == true && | |
| serverInterface->getAllowInGameConnections() == true) { | |
| this->serverInterface->gameSettings.setNetworkPlayerStatuses(factionIndex,npst_None); | |
| } | |
| if(getAllowGameDataSynchCheck() == true && serverInterface->getGameSettings() != NULL) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] sending NetworkMessageSynchNetworkGameData\n",__FILE__,__FUNCTION__,__LINE__); | |
| NetworkMessageSynchNetworkGameData networkMessageSynchNetworkGameData(serverInterface->getGameSettings()); | |
| sendMessage(&networkMessageSynchNetworkGameData); | |
| } | |
| if(serverInterface->getGameHasBeenInitiated() == true && | |
| serverInterface->getAllowInGameConnections() == true) { | |
| ConnectionSlot *slot = serverInterface->findSlotForUUID(this->playerUUID,true); | |
| if(slot != NULL) { | |
| slot->setJoinGameInProgressFlags(); | |
| slot->setPauseForInGameConnection(true); | |
| serverInterface->switchSlot(this->playerIndex,slot->getPlayerIndex()); | |
| } | |
| else { | |
| setJoinGameInProgressFlags(); | |
| this->setPauseForInGameConnection(true); | |
| } | |
| } | |
| else { | |
| ConnectionSlot *slot = serverInterface->findSlotForUUID(this->playerUUID,true); | |
| if(slot != NULL) { | |
| serverInterface->switchSlot(this->playerIndex,slot->getPlayerIndex()); | |
| } | |
| } | |
| } | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| break; | |
| case nmtLaunch: | |
| case nmtBroadCastSetup: | |
| { | |
| if(gotIntro == true) { | |
| if(this->serverInterface->getGameSettings() == NULL || | |
| (joinGameInProgress == false && sessionKey != this->serverInterface->getGameSettings()->getMasterserver_admin())) { | |
| string playerNameStr = name; | |
| string sErr = "Client has invalid admin sessionid for player [" + playerNameStr + "]"; | |
| printf("%s\n",sErr.c_str()); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,sErr.c_str()); | |
| close(); | |
| return; | |
| } | |
| NetworkMessageLaunch networkMessageLaunch; | |
| if(receiveMessage(&networkMessageLaunch,networkMessageType)) { | |
| if(networkMessageLaunch.getMessageType() == nmtLaunch) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got nmtLaunch\n",__FILE__,__FUNCTION__,__LINE__); | |
| //printf("Got launch request from client joinGameInProgress = %d joinGameInProgress = %d!\n",joinGameInProgress,joinGameInProgress); | |
| } | |
| else if(networkMessageLaunch.getMessageType() == nmtBroadCastSetup) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got nmtBroadCastSetup\n",__FILE__,__FUNCTION__,__LINE__); | |
| } | |
| else { | |
| 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()); | |
| char szBuf[1024]=""; | |
| snprintf(szBuf,1023,"In [%s::%s Line: %d] Invalid networkMessageLaunch.getMessageType() = %d",__FILE__,__FUNCTION__,__LINE__,networkMessageLaunch.getMessageType()); | |
| throw megaglest_runtime_error(szBuf); | |
| } | |
| int minHeadLessPlayersRequired = Config::getInstance().getInt("MinHeadlessPlayersRequired","2"); | |
| if(this->joinGameInProgress == false && | |
| networkMessageLaunch.getMessageType() == nmtLaunch && | |
| this->ready == false && | |
| this->serverInterface->getConnectedSlotCount(true) < minHeadLessPlayersRequired) { | |
| Lang &lang= Lang::getInstance(); | |
| const vector<string> languageList = this->serverInterface->getGameSettings()->getUniqueNetworkPlayerLanguages(); | |
| for(unsigned int index = 0; index < languageList.size(); ++index) { | |
| char szBuf[4096]=""; | |
| string msgTemplate = "You must have have at least %d player(s) connected to start this game!"; | |
| if(lang.hasString("HeadlessAdminRequiresMorePlayers",languageList[index]) == true) { | |
| msgTemplate = lang.getString("HeadlessAdminRequiresMorePlayers",languageList[index]); | |
| } | |
| #ifdef WIN32 | |
| _snprintf(szBuf,4095,msgTemplate.c_str(),minHeadLessPlayersRequired); | |
| #else | |
| snprintf(szBuf,4095,msgTemplate.c_str(),minHeadLessPlayersRequired); | |
| #endif | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,szBuf); | |
| string sMsg = szBuf; | |
| bool echoLocal = lang.isLanguageLocal(languageList[index]); | |
| this->serverInterface->sendTextMessage(sMsg,-1, echoLocal, languageList[index], this->getPlayerIndex()); | |
| } | |
| } | |
| else { | |
| if(this->joinGameInProgress == false) { | |
| GameSettings gameSettingsBuffer; | |
| networkMessageLaunch.buildGameSettings(&gameSettingsBuffer); | |
| //printf("Connection slot got networkMessageLaunch.getMessageType() = %d, got map [%s]\n",networkMessageLaunch.getMessageType(),gameSettings.getMap().c_str()); | |
| //printf("\n\n\n\n=====Connection slot got settings:\n%s\n",gameSettings.toString().c_str()); | |
| this->serverInterface->broadcastGameSetup(&gameSettingsBuffer, true); | |
| } | |
| if(this->joinGameInProgress == false && | |
| networkMessageLaunch.getMessageType() == nmtLaunch) { | |
| this->serverInterface->setMasterserverAdminRequestLaunch(true); | |
| } | |
| else if(this->joinGameInProgress == true && | |
| networkMessageLaunch.getMessageType() == nmtLaunch) { | |
| //printf("!!! setStartInGameConnectionLaunch for client joinGameInProgress = %d!\n",joinGameInProgress); | |
| int factionIndex = this->serverInterface->gameSettings.getFactionIndexForStartLocation(playerIndex); | |
| this->serverInterface->gameSettings.setFactionControl(factionIndex,ctNetwork); | |
| this->serverInterface->gameSettings.setNetworkPlayerName(factionIndex,this->name); | |
| this->serverInterface->gameSettings.setNetworkPlayerUUID(factionIndex,this->playerUUID); | |
| this->serverInterface->gameSettings.setNetworkPlayerPlatform(factionIndex,this->platform); | |
| if(this->serverInterface->gameSettings.getNetworkPlayerStatuses(factionIndex) == npst_Disconnected) { | |
| this->serverInterface->gameSettings.setNetworkPlayerStatuses(factionIndex,npst_None); | |
| } | |
| this->serverInterface->broadcastGameSetup(&this->serverInterface->gameSettings, true); | |
| this->setStartInGameConnectionLaunch(true); | |
| } | |
| } | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| break; | |
| //process datasynch messages | |
| case nmtSynchNetworkGameDataStatus: | |
| { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtSynchNetworkGameDataStatus, gotIntro = %d\n",__FILE__,__FUNCTION__,__LINE__,gotIntro); | |
| if(gotIntro == true) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| NetworkMessageSynchNetworkGameDataStatus networkMessageSynchNetworkGameDataStatus; | |
| if(receiveMessage(&networkMessageSynchNetworkGameDataStatus)) { | |
| this->setNetworkGameDataSynchCheckTechMismatchReport(""); | |
| this->setReceivedDataSynchCheck(false); | |
| Config &config = Config::getInstance(); | |
| string scenarioDir = ""; | |
| if(serverInterface->getGameSettings()->getScenarioDir() != "") { | |
| scenarioDir = serverInterface->getGameSettings()->getScenarioDir(); | |
| if(EndsWith(scenarioDir, ".xml") == true) { | |
| scenarioDir = scenarioDir.erase(scenarioDir.size() - 4, 4); | |
| scenarioDir = scenarioDir.erase(scenarioDir.size() - serverInterface->getGameSettings()->getScenario().size(), serverInterface->getGameSettings()->getScenario().size() + 1); | |
| } | |
| 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()); | |
| } | |
| //tileset | |
| uint32 tilesetCRC = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptTilesets,scenarioDir), string("/") + serverInterface->getGameSettings()->getTileset() + string("/*"), ".xml", NULL); | |
| uint32 techCRC = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptTechs,scenarioDir), "/" + serverInterface->getGameSettings()->getTech() + "/*", ".xml", NULL); | |
| Checksum checksum; | |
| string file = Config::getMapPath(serverInterface->getGameSettings()->getMap(),scenarioDir,false); | |
| checksum.addFile(file); | |
| uint32 mapCRC = checksum.getSum(); | |
| networkGameDataSynchCheckOkMap = (networkMessageSynchNetworkGameDataStatus.getMapCRC() == mapCRC); | |
| networkGameDataSynchCheckOkTile = (networkMessageSynchNetworkGameDataStatus.getTilesetCRC() == tilesetCRC); | |
| networkGameDataSynchCheckOkTech = (networkMessageSynchNetworkGameDataStatus.getTechCRC() == techCRC); | |
| // For testing | |
| //techCRC++; | |
| if( networkGameDataSynchCheckOkMap == true && | |
| networkGameDataSynchCheckOkTile == true && | |
| networkGameDataSynchCheckOkTech == true) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] client data synch ok\n",__FILE__,__FUNCTION__); | |
| } | |
| else { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] mapCRC = %d, remote = %d\n",__FILE__,__FUNCTION__,mapCRC,networkMessageSynchNetworkGameDataStatus.getMapCRC()); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] tilesetCRC = %d, remote = %d\n",__FILE__,__FUNCTION__,tilesetCRC,networkMessageSynchNetworkGameDataStatus.getTilesetCRC()); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] techCRC = %d, remote = %d\n",__FILE__,__FUNCTION__,techCRC,networkMessageSynchNetworkGameDataStatus.getTechCRC()); | |
| if(allowDownloadDataSynch == true) { | |
| // Now get all filenames with their CRC values and send to the client | |
| vctFileList.clear(); | |
| Config &config = Config::getInstance(); | |
| string scenarioDir = ""; | |
| if(serverInterface->getGameSettings()->getScenarioDir() != "") { | |
| scenarioDir = serverInterface->getGameSettings()->getScenarioDir(); | |
| if(EndsWith(scenarioDir, ".xml") == true) { | |
| scenarioDir = scenarioDir.erase(scenarioDir.size() - 4, 4); | |
| scenarioDir = scenarioDir.erase(scenarioDir.size() - serverInterface->getGameSettings()->getScenario().size(), serverInterface->getGameSettings()->getScenario().size() + 1); | |
| } | |
| 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()); | |
| } | |
| if(networkGameDataSynchCheckOkTile == false) { | |
| if(tilesetCRC == 0) { | |
| vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTilesets,scenarioDir), string("/") + serverInterface->getGameSettings()->getTileset() + string("/*"), "", &vctFileList); | |
| } | |
| else { | |
| vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTilesets,scenarioDir), "/" + serverInterface->getGameSettings()->getTileset() + "/*", ".xml", &vctFileList); | |
| } | |
| } | |
| if(networkGameDataSynchCheckOkTech == false) { | |
| if(techCRC == 0) { | |
| vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTechs,scenarioDir),"/" + serverInterface->getGameSettings()->getTech() + "/*", "", &vctFileList); | |
| } | |
| else { | |
| vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTechs,scenarioDir),"/" + serverInterface->getGameSettings()->getTech() + "/*", ".xml", &vctFileList); | |
| } | |
| string report = networkMessageSynchNetworkGameDataStatus.getTechCRCFileMismatchReport(serverInterface->getGameSettings()->getTech(),vctFileList); | |
| this->setNetworkGameDataSynchCheckTechMismatchReport(report); | |
| } | |
| if(networkGameDataSynchCheckOkMap == false) { | |
| vctFileList.push_back(std::pair<string,uint32>(Config::getMapPath(serverInterface->getGameSettings()->getMap(),scenarioDir,false),mapCRC)); | |
| } | |
| NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck((int)vctFileList.size(), 1, vctFileList[0].second, vctFileList[0].first); | |
| sendMessage(&networkMessageSynchNetworkGameDataFileCRCCheck); | |
| } | |
| else { | |
| if(networkGameDataSynchCheckOkTech == false) { | |
| vctFileList = getFolderTreeContentsCheckSumListRecursively(config.getPathListForType(ptTechs,scenarioDir),"/" + serverInterface->getGameSettings()->getTech() + "/*", ".xml", NULL); | |
| string report = networkMessageSynchNetworkGameDataStatus.getTechCRCFileMismatchReport(serverInterface->getGameSettings()->getTech(),vctFileList); | |
| this->setNetworkGameDataSynchCheckTechMismatchReport(report); | |
| } | |
| } | |
| } | |
| this->setReceivedDataSynchCheck(true); | |
| receivedNetworkGameStatus = true; | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| break; | |
| case nmtSynchNetworkGameDataFileCRCCheck: | |
| { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtSynchNetworkGameDataFileCRCCheck\n",__FILE__,__FUNCTION__); | |
| if(gotIntro == true) { | |
| NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck; | |
| if(receiveMessage(&networkMessageSynchNetworkGameDataFileCRCCheck)) | |
| { | |
| int fileIndex = networkMessageSynchNetworkGameDataFileCRCCheck.getFileIndex(); | |
| NetworkMessageSynchNetworkGameDataFileCRCCheck networkMessageSynchNetworkGameDataFileCRCCheck((int)vctFileList.size(), fileIndex, vctFileList[fileIndex-1].second, vctFileList[fileIndex-1].first); | |
| sendMessage(&networkMessageSynchNetworkGameDataFileCRCCheck); | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| break; | |
| case nmtSynchNetworkGameDataFileGet: | |
| { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] got nmtSynchNetworkGameDataFileGet\n",__FILE__,__FUNCTION__); | |
| if(gotIntro == true) { | |
| NetworkMessageSynchNetworkGameDataFileGet networkMessageSynchNetworkGameDataFileGet; | |
| if(receiveMessage(&networkMessageSynchNetworkGameDataFileGet)) { | |
| FileTransferInfo fileInfo; | |
| fileInfo.hostType = eServer; | |
| //fileInfo.serverIP = this->ip.getString(); | |
| fileInfo.serverPort = Config::getInstance().getInt("PortServer",intToStr(GameConstants::serverPort).c_str()); | |
| fileInfo.fileName = networkMessageSynchNetworkGameDataFileGet.getFileName(); | |
| FileTransferSocketThread *fileXferThread = new FileTransferSocketThread(fileInfo); | |
| fileXferThread->start(); | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| break; | |
| case nmtSwitchSetupRequest: | |
| { | |
| //printf("Got nmtSwitchSetupRequest A gotIntro = %d\n",gotIntro); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got nmtSwitchSetupRequest gotIntro = %d\n",__FILE__,__FUNCTION__,__LINE__,gotIntro); | |
| if(gotIntro == true) { | |
| //printf("Got nmtSwitchSetupRequest B\n"); | |
| SwitchSetupRequest switchSetupRequest; | |
| if(receiveMessage(&switchSetupRequest)) { | |
| MutexSafeWrapper safeMutex(getServerSynchAccessor(),CODE_AT_LINE); | |
| int slotIdx = switchSetupRequest.getCurrentSlotIndex(); | |
| //int newSlotIdx = switchSetupRequest.getToSlotIndex(); | |
| //printf("slotIdx = %d newSlotIdx = %d\n",slotIdx,newSlotIdx); | |
| if(serverInterface->getSwitchSetupRequests(slotIdx) == NULL) { | |
| serverInterface->setSwitchSetupRequests(slotIdx,new SwitchSetupRequest()); | |
| } | |
| *(serverInterface->getSwitchSetupRequests(slotIdx)) = switchSetupRequest; | |
| //printf("slotIdx = %d newSlotIdx = %d\n",serverInterface->getSwitchSetupRequests(slotIdx)->getCurrentSlotIndex(),serverInterface->getSwitchSetupRequests(slotIdx)->getToSlotIndex()); | |
| this->playerStatus = switchSetupRequest.getNetworkPlayerStatus(); | |
| this->name = switchSetupRequest.getNetworkPlayerName(); | |
| this->playerLanguage = switchSetupRequest.getNetworkPlayerLanguage(); | |
| //printf("Got nmtSwitchSetupRequest C\n"); | |
| //printf("In [%s::%s Line %d] networkPlayerName [%s]\n",__FILE__,__FUNCTION__,__LINE__,serverInterface->getSwitchSetupRequests()[factionIdx]->getNetworkPlayerName().c_str()); | |
| if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line %d] networkPlayerName [%s]\n",__FILE__,__FUNCTION__,__LINE__,serverInterface->getSwitchSetupRequests()[slotIdx]->getNetworkPlayerName().c_str()); | |
| 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()); | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| else { | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| break; | |
| } | |
| case nmtReady: | |
| { | |
| NetworkMessageReady networkMessageReady; | |
| this->receiveMessage(&networkMessageReady); | |
| // its simply ignored here. Probably we are starting a game | |
| //printf("Got ready message from client slot joinGameInProgress = %d\n",joinGameInProgress); | |
| if(joinGameInProgress == true) { | |
| NetworkMessageReady networkMessageReady(0); | |
| this->sendMessage(&networkMessageReady); | |
| this->setGameStarted(true); | |
| this->currentFrameCount = serverInterface->getCurrentFrameCount(); | |
| //printf("#2 Server slot got currentFrameCount = %d\n",currentFrameCount); | |
| this->currentLagCount = 0; | |
| this->lastReceiveCommandListTime = time(NULL); | |
| this->setReady(); | |
| } | |
| // unpause the game | |
| else { | |
| this->setUnPauseForInGameConnection(true); | |
| } | |
| break; | |
| } | |
| case nmtLoadingStatusMessage: | |
| break; | |
| default: | |
| { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] networkMessageType = %d\n",__FILE__,__FUNCTION__,__LINE__,networkMessageType); | |
| if(gotIntro == true) { | |
| //throw megaglest_runtime_error("Unexpected message in connection slot: " + intToStr(networkMessageType)); | |
| string sErr = "Unexpected message in connection slot: " + intToStr(networkMessageType); | |
| //sendTextMessage(sErr,-1); | |
| //DisplayErrorMessage(sErr); | |
| threadErrorList.push_back(sErr); | |
| return; | |
| } | |
| else { | |
| 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__); | |
| 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()); | |
| this->serverInterface->notifyBadClientConnectAttempt(this->getIpAddress()); | |
| close(); | |
| return; | |
| } | |
| } | |
| } | |
| //printf("#3 Server slot got currentFrameCount = %d\n",currentFrameCount); | |
| // This may end up continuously lagging and not disconnecting players who have | |
| // just the 'wrong' amount of lag (but not enough to be horrible for a disconnect) | |
| if(Config::getInstance().getBool("AutoClientLagCorrection","true") == true) { | |
| double LAG_CHECK_GRACE_PERIOD = 15; | |
| //printf("#4 Server slot got currentFrameCount = %d\n",currentFrameCount); | |
| if(this->serverInterface->getGameStartTime() > 0 && | |
| difftime((long int)time(NULL),this->serverInterface->getGameStartTime()) >= LAG_CHECK_GRACE_PERIOD && | |
| difftime((long int)time(NULL),this->getConnectedTime()) >= LAG_CHECK_GRACE_PERIOD) { | |
| if(this->isConnected() == true && this->gotIntro == true && this->skipLagCheck == false) { | |
| double clientLag = this->serverInterface->getCurrentFrameCount() - this->getCurrentFrameCount(); | |
| double clientLagCount = (gameSettings.getNetworkFramePeriod() > 0 ? (clientLag / gameSettings.getNetworkFramePeriod()) : 0); | |
| double clientLagTime = difftime((long int)time(NULL),this->getLastReceiveCommandListTime()); | |
| double maxFrameCountLagAllowed = 10; | |
| double maxClientLagTimeAllowed = 8; | |
| // New lag check | |
| if((clientLagCount > maxFrameCountLagAllowed) || | |
| (maxClientLagTimeAllowed > 0 && clientLagTime > maxClientLagTimeAllowed)) { | |
| waitForLaggingClient = true; | |
| if(waitedForLaggingClient == false) { | |
| waitedForLaggingClient = true; | |
| printf("*TESTING*: START Waiting for lagging client playerIndex = %d [%s] clientLagCount = %f [%f]\n",playerIndex,name.c_str(),clientLagCount,clientLagTime); | |
| } | |
| } | |
| } | |
| } | |
| //printf("#5 Server slot got currentFrameCount = %d\n",currentFrameCount); | |
| } | |
| //printf("#5a Server slot got currentFrameCount = %d\n",currentFrameCount); | |
| } | |
| //printf("#6 Server slot got currentFrameCount = %d\n",currentFrameCount); | |
| if(waitedForLaggingClient == true) { | |
| printf("*TESTING*: FINISHED Waiting for lagging client playerIndex = %d [%s]\n",playerIndex,name.c_str()); | |
| } | |
| //if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis()); | |
| validateConnection(); | |
| //printf("#7 Server slot got currentFrameCount = %d\n",currentFrameCount); | |
| //if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis()); | |
| } | |
| else { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] calling close...\n",__FILE__,__FUNCTION__,__LINE__); | |
| //printf("Closing connection slot socketInfo.first = %d\n",socketInfo.first); | |
| close(); | |
| //if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis()); | |
| } | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| } | |
| } | |
| catch(const exception &ex) { | |
| SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); | |
| threadErrorList.push_back(ex.what()); | |
| //if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis()); | |
| } | |
| //printf("#8 Server slot got currentFrameCount = %d\n",currentFrameCount); | |
| //if(chrono.getMillis() > 1) printf("In [%s::%s Line: %d] action running for msecs: %lld\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis()); | |
| } | |
| void ConnectionSlot::validateConnection() { | |
| if(this->isConnected() == true && | |
| gotIntro == false && connectedTime > 0 && | |
| difftime((long int)time(NULL),connectedTime) > GameConstants::maxClientConnectHandshakeSecs) { | |
| //printf("Closing connection slot timed out!\n"); | |
| close(); | |
| } | |
| } | |
| //void ConnectionSlot::resetJoinGameInProgressFlags() { | |
| // this->gotIntro = false; | |
| // this->skipLagCheck = false; | |
| // this->joinGameInProgress = false; | |
| // this->ready = false; | |
| //} | |
| void ConnectionSlot::setJoinGameInProgressFlags() { | |
| this->gotIntro = true; | |
| this->skipLagCheck = true; | |
| this->joinGameInProgress = true; | |
| this->ready = false; | |
| this->sentSavedGameInfo = false; | |
| } | |
| void ConnectionSlot::close() { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s LINE: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| //printf("Closing slot for playerIndex = %d\n",playerIndex); | |
| //if(serverInterface->getAllowInGameConnections() == true) { | |
| //printf("Closing connection slot!\n"); | |
| //} | |
| //printf("ConnectionSlot::close() #1 this->getSocket() = %p\n",this->getSocket()); | |
| this->gotIntro = false; | |
| this->skipLagCheck = false; | |
| this->joinGameInProgress = false; | |
| this->sentSavedGameInfo = false; | |
| this->pauseForInGameConnection = false; | |
| this->unPauseForInGameConnection = false; | |
| this->ready = false; | |
| this->connectedTime = 0; | |
| if(this->slotThreadWorker != NULL) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| this->slotThreadWorker->setAllEventsCompleted(); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| } | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| //printf("ConnectionSlot::close() #2 this->getSocket() = %p\n",this->getSocket()); | |
| MutexSafeWrapper safeMutex(mutexCloseConnection,CODE_AT_LINE); | |
| bool updateServerListener = (this->getSocket() != NULL); | |
| //printf("ConnectionSlot::close() #3 this->getSocket() = %p updateServerListener = %d\n",this->getSocket(),updateServerListener); | |
| this->deleteSocket(); | |
| safeMutex.ReleaseLock(); | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s LINE: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| //printf("Closing slot for playerIndex = %d updateServerListener = %d ready = %d\n",playerIndex,updateServerListener,ready); | |
| if(updateServerListener == true) { | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s LINE: %d]\n",__FILE__,__FUNCTION__,__LINE__); | |
| serverInterface->updateListen(); | |
| } | |
| if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END\n",__FILE__,__FUNCTION__); | |
| } | |
| Mutex * ConnectionSlot::getServerSynchAccessor() { | |
| return (serverInterface != NULL ? serverInterface->getServerSynchAccessor() : NULL); | |
| } | |
| void ConnectionSlot::signalUpdate(ConnectionSlotEvent *event) { | |
| if(slotThreadWorker != NULL) { | |
| slotThreadWorker->signalUpdate(event); | |
| } | |
| } | |
| bool ConnectionSlot::updateCompleted(ConnectionSlotEvent *event) { | |
| bool waitingForThread = (slotThreadWorker != NULL && | |
| slotThreadWorker->isSignalCompleted(event) == false && | |
| slotThreadWorker->getQuitStatus() == false && | |
| slotThreadWorker->getRunningStatus() == true); | |
| return (waitingForThread == false); | |
| } | |
| void ConnectionSlot::sendMessage(NetworkMessage* networkMessage) { | |
| MutexSafeWrapper safeMutex(socketSynchAccessor,CODE_AT_LINE); | |
| // Skip text messages not intended for the players preferred language | |
| NetworkMessageText *textMsg = dynamic_cast<NetworkMessageText *>(networkMessage); | |
| if(textMsg != NULL) { | |
| //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()); | |
| if(textMsg->getTargetLanguage() != "" && | |
| textMsg->getTargetLanguage() != this->getNetworkPlayerLanguage()) { | |
| return; | |
| } | |
| } | |
| NetworkInterface::sendMessage(networkMessage); | |
| } | |
| string ConnectionSlot::getHumanPlayerName(int index) { | |
| return serverInterface->getHumanPlayerName(index); | |
| } | |
| vector<NetworkCommand> ConnectionSlot::getPendingNetworkCommandList(bool clearList) { | |
| vector<NetworkCommand> ret; | |
| MutexSafeWrapper safeMutexSlot(mutexPendingNetworkCommandList,CODE_AT_LINE); | |
| if(vctPendingNetworkCommandList.empty() == false) { | |
| ret = vctPendingNetworkCommandList; | |
| if(clearList == true) { | |
| vctPendingNetworkCommandList.clear(); | |
| } | |
| } | |
| return ret; | |
| } | |
| //void ConnectionSlot::clearPendingNetworkCommandList() { | |
| // MutexSafeWrapper safeMutexSlot(mutexPendingNetworkCommandList,CODE_AT_LINE); | |
| // if(vctPendingNetworkCommandList.empty() == false) { | |
| // vctPendingNetworkCommandList.clear(); | |
| // } | |
| //} | |
| bool ConnectionSlot::hasValidSocketId() { | |
| bool result = false; | |
| MutexSafeWrapper safeMutexSlot(mutexSocket,CODE_AT_LINE); | |
| if(socket != NULL && socket->getSocketId() > 0) { | |
| result = true; | |
| } | |
| return result; | |
| } | |
| bool ConnectionSlot::isConnected() { | |
| bool result = false; | |
| MutexSafeWrapper safeMutexSlot(mutexSocket,CODE_AT_LINE); | |
| if(socket != NULL && socket->isConnected() == true) { | |
| result = true; | |
| } | |
| return result; | |
| } | |
| PLATFORM_SOCKET ConnectionSlot::getSocketId() { | |
| PLATFORM_SOCKET result = 0; | |
| MutexSafeWrapper safeMutexSlot(mutexSocket,CODE_AT_LINE); | |
| if(socket != NULL) { | |
| result = socket->getSocketId(); | |
| } | |
| return result; | |
| } | |
| pair<bool,Socket*> ConnectionSlot::getSocketInfo() { | |
| pair<bool,Socket*> result; | |
| MutexSafeWrapper safeMutexSlot(mutexSocket,CODE_AT_LINE); | |
| result.first = (socket != NULL && socket->isConnected()); | |
| result.second = socket; | |
| return result; | |
| } | |
| Socket* ConnectionSlot::getSocket(bool mutexLock) { | |
| MutexSafeWrapper safeMutexSlot(NULL,CODE_AT_LINE); | |
| if(mutexLock == true) { | |
| safeMutexSlot.setMutex(mutexSocket,CODE_AT_LINE); | |
| } | |
| return socket; | |
| } | |
| void ConnectionSlot::setSocket(Socket *newSocket) { | |
| MutexSafeWrapper safeMutexSlot(mutexSocket,CODE_AT_LINE); | |
| socket = newSocket; | |
| } | |
| void ConnectionSlot::deleteSocket() { | |
| MutexSafeWrapper safeMutexSlot(mutexSocket,CODE_AT_LINE); | |
| delete socket; | |
| socket = NULL; | |
| } | |
| bool ConnectionSlot::hasDataToRead() { | |
| bool result = false; | |
| MutexSafeWrapper safeMutexSlot(mutexSocket,CODE_AT_LINE); | |
| if(socket != NULL && socket->hasDataToRead() == true) { | |
| result = true; | |
| } | |
| return result; | |
| } | |
| }}//end namespace |