// ============================================================== // 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 "network_interface.h" #include #include #include "data_types.h" #include "conversion.h" #include "platform_util.h" #include #include "util.h" #include "network_protocol.h" #include "leak_dumper.h" using namespace Shared::Platform; using namespace Shared::Util; using namespace std; namespace Glest{ namespace Game{ // ===================================================== // class NetworkInterface // ===================================================== const int NetworkInterface::readyWaitTimeout= 180000; // 3 minutes bool NetworkInterface::allowGameDataSynchCheck = false; bool NetworkInterface::allowDownloadDataSynch = false; DisplayMessageFunction NetworkInterface::pCB_DisplayMessage = NULL; Vec3f MarkedCell::static_system_marker_color(MAGENTA.x,MAGENTA.y,MAGENTA.z); NetworkInterface::NetworkInterface() { networkAccessMutex = new Mutex(CODE_AT_LINE); networkGameDataSynchCheckOkMap=false; networkGameDataSynchCheckOkTile=false; networkGameDataSynchCheckOkTech=false; receivedDataSynchCheck=false; networkPlayerFactionCRCMutex = new Mutex(CODE_AT_LINE); for(unsigned int index = 0; index < (unsigned int)GameConstants::maxPlayers; ++index) { networkPlayerFactionCRC[index] = 0; } } void NetworkInterface::init() { networkAccessMutex = NULL; networkGameDataSynchCheckOkMap=false; networkGameDataSynchCheckOkTile=false; networkGameDataSynchCheckOkTech=false; receivedDataSynchCheck=false; gameSettings = GameSettings(); networkPlayerFactionCRCMutex = NULL; for(unsigned int index = 0; index < (unsigned int)GameConstants::maxPlayers; ++index) { networkPlayerFactionCRC[index] = 0; } } NetworkInterface::~NetworkInterface() { delete networkAccessMutex; networkAccessMutex = NULL; delete networkPlayerFactionCRCMutex; networkPlayerFactionCRCMutex = NULL; } uint32 NetworkInterface::getNetworkPlayerFactionCRC(int index) { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkPlayerFactionCRCMutex,mutexOwnerId); return networkPlayerFactionCRC[index]; } void NetworkInterface::setNetworkPlayerFactionCRC(int index, uint32 crc) { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkPlayerFactionCRCMutex,mutexOwnerId); networkPlayerFactionCRC[index]=crc; } void NetworkInterface::addChatInfo(const ChatMsgInfo &msg) { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); chatTextList.push_back(msg); } void NetworkInterface::addMarkedCell(const MarkedCell &msg) { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); markedCellList.push_back(msg); } void NetworkInterface::addUnMarkedCell(const UnMarkedCell &msg) { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); unmarkedCellList.push_back(msg); } void NetworkInterface::sendMessage(NetworkMessage* networkMessage){ Socket* socket= getSocket(false); networkMessage->send(socket); } NetworkMessageType NetworkInterface::getNextMessageType(int waitMilliseconds) { Socket* socket= getSocket(false); int8 messageType= nmtInvalid; if(socket != NULL && ((waitMilliseconds <= 0 && socket->hasDataToRead() == true) || (waitMilliseconds > 0 && socket->hasDataToReadWithWait(waitMilliseconds) == true))) { //peek message type int dataSize = socket->getDataToRead(); if(dataSize >= (int)sizeof(messageType)) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] socket->getDataToRead() dataSize = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,dataSize); int iPeek = socket->peek(&messageType, sizeof(messageType)); if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] socket->getDataToRead() iPeek = %d, messageType = %d [size = %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,iPeek,messageType,sizeof(messageType)); } else { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] PEEK WARNING, socket->getDataToRead() messageType = %d [size = %d], dataSize = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,messageType,sizeof(messageType),dataSize); } //sanity check new message type if(messageType < 0 || messageType >= nmtCount) { if(getConnectHasHandshaked() == true) { throw megaglest_runtime_error("Invalid message type: " + intToStr(messageType)); } else { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] Invalid message type = %d (no packet handshake yet so ignored)\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,messageType); } } } return static_cast(messageType); } bool NetworkInterface::receiveMessage(NetworkMessage* networkMessage){ if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__); Socket* socket= getSocket(false); return networkMessage->receive(socket); } bool NetworkInterface::isConnected(){ bool result = (getSocket()!=NULL && getSocket()->isConnected()); return result; } void NetworkInterface::setLastPingInfo(const NetworkMessagePing &ping) { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); this->lastPingInfo = ping; } void NetworkInterface::setLastPingInfoToNow() { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); this->lastPingInfo.setPingReceivedLocalTime(time(NULL)); } NetworkMessagePing NetworkInterface::getLastPingInfo() { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); return lastPingInfo; } double NetworkInterface::getLastPingLag() { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); return difftime((long int)time(NULL),lastPingInfo.getPingReceivedLocalTime()); } void NetworkInterface::DisplayErrorMessage(string sErr, bool closeSocket) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] sErr [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,sErr.c_str()); SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] sErr [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,sErr.c_str()); if(closeSocket == true && getSocket() != NULL) { close(); } if(pCB_DisplayMessage != NULL) { pCB_DisplayMessage(sErr.c_str(), false); } else { throw megaglest_runtime_error(sErr); } } std::vector NetworkInterface::getChatTextList(bool clearList) { std::vector result; static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); if(chatTextList.empty() == false) { result = chatTextList; if(clearList == true) { chatTextList.clear(); } } return result; } void NetworkInterface::clearChatInfo() { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); if(chatTextList.empty() == false) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] chatTextList.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chatTextList.size()); chatTextList.clear(); } } std::vector NetworkInterface::getMarkedCellList(bool clearList) { std::vector result; static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); if(markedCellList.empty() == false) { result = markedCellList; if(clearList == true) { markedCellList.clear(); } } return result; } void NetworkInterface::clearMarkedCellList() { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); if(markedCellList.empty() == false) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] markedCellList.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,markedCellList.size()); markedCellList.clear(); } } std::vector NetworkInterface::getUnMarkedCellList(bool clearList) { std::vector result; static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); if(unmarkedCellList.empty() == false) { result = unmarkedCellList; if(clearList == true) { unmarkedCellList.clear(); } } return result; } void NetworkInterface::clearUnMarkedCellList() { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); if(unmarkedCellList.empty() == false) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] unmarkedCellList.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,unmarkedCellList.size()); unmarkedCellList.clear(); } } std::vector NetworkInterface::getHighlightedCellList(bool clearList) { std::vector result; static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); if(highlightedCellList.empty() == false) { result = highlightedCellList; if(clearList == true) { highlightedCellList.clear(); } } return result; } void NetworkInterface::clearHighlightedCellList() { static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); if(highlightedCellList.empty() == false) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] markedCellList.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,markedCellList.size()); highlightedCellList.clear(); } } void NetworkInterface::setHighlightedCell(const MarkedCell &msg){ static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); for(int idx = 0; idx < (int)highlightedCellList.size(); idx++) { MarkedCell mc = highlightedCellList[idx]; if(mc.getFactionIndex()==msg.getFactionIndex()){ highlightedCellList.erase(highlightedCellList.begin()+ idx); break; } } highlightedCellList.push_back(msg); } float NetworkInterface::getThreadedPingMS(std::string host) { float result = -1; if(getSocket() != NULL) { result = getSocket()->getThreadedPingMS(host); } return result; } // ===================================================== // class GameNetworkInterface // ===================================================== GameNetworkInterface::GameNetworkInterface(){ quit= false; } void GameNetworkInterface::requestCommand(const NetworkCommand *networkCommand, bool insertAtStart) { assert(networkCommand != NULL); Mutex *mutex = getServerSynchAccessor(); if(insertAtStart == false) { MutexSafeWrapper safeMutex(mutex,string(__FILE__) + "_" + intToStr(__LINE__)); requestedCommands.push_back(*networkCommand); } else { MutexSafeWrapper safeMutex(mutex,string(__FILE__) + "_" + intToStr(__LINE__)); requestedCommands.insert(requestedCommands.begin(),*networkCommand); } } // ===================================================== // class FileTransferSocketThread // ===================================================== const int32 SEND_FILE = 0x20; const int32 ACK = 0x47; FileTransferSocketThread::FileTransferSocketThread(FileTransferInfo fileInfo) : info(fileInfo) { this->info.serverPort += 100; } void FileTransferSocketThread::execute() { if(info.hostType == eServer) { ServerSocket serverSocket; serverSocket.bind(this->info.serverPort); serverSocket.listen(1); Socket *clientSocket = serverSocket.accept(); char data[513]=""; memset(data, 0, 256); clientSocket->receive(data,256, true); if(*data == SEND_FILE) { FileInfo file; memcpy(&file, data+1, sizeof(file)); *data=ACK; clientSocket->send(data,256); Checksum checksum; checksum.addFile(file.fileName); file.filecrc = checksum.getSum(); ifstream infile(file.fileName.c_str(), ios::in | ios::binary | ios::ate); if(infile.is_open() == true) { file.filesize = infile.tellg(); infile.seekg (0, ios::beg); memset(data, 0, 256); *data=SEND_FILE; memcpy(data+1,&file,sizeof(file)); clientSocket->send(data,256); clientSocket->receive(data,256, true); if(*data != ACK) { //transfer error } int remain=file.filesize % 512 ; int packs=(file.filesize-remain)/512; while(packs--) { infile.read(data,512); //if(!ReadFile(file,data,512,&read,NULL)) // ; //read error //if(written!=pack) // ; //read error clientSocket->send(data,512); clientSocket->receive(data,256, true); if(*data!=ACK) { //transfer error } } infile.read(data,remain); //if(!ReadFile(file,data,remain,&read,NULL)) // ; //read error //if(written!=pack) // ; //read error clientSocket->send(data,remain); clientSocket->receive(data,256, true); if(*data!=ACK) { //transfer error } infile.close(); } } delete clientSocket; } else { Ip ip(this->info.serverIP); ClientSocket clientSocket; clientSocket.connect(this->info.serverIP, this->info.serverPort); if(clientSocket.isConnected() == true) { FileInfo file; file.fileName = this->info.fileName; //file.filesize = //file.filecrc = this->info. string path = extractDirectoryPathFromFile(file.fileName); createDirectoryPaths(path); ofstream outFile(file.fileName.c_str(), ios_base::binary | ios_base::out); if(outFile.is_open() == true) { char data[513]=""; memset(data, 0, 256); *data=SEND_FILE; memcpy(data+1,&file,sizeof(file)); clientSocket.send(data,256); clientSocket.receive(data,256, true); if(*data!=ACK) { //transfer error } clientSocket.receive(data,256,true); if(*data == SEND_FILE) { memcpy(&file, data+1, sizeof(file)); *data=ACK; clientSocket.send(data,256); int remain = file.filesize % 512 ; int packs = (file.filesize-remain) / 512; while(packs--) { clientSocket.receive(data,512,true); outFile.write(data, 512); if(outFile.bad()) { //int ii = 0; } //if(!WriteFile(file,data,512,&written,NULL)) // ; //write error //if(written != pack) // ; //write error *data=ACK; clientSocket.send(data,256); } clientSocket.receive(data,remain,true); outFile.write(data, remain); if(outFile.bad()) { //int ii = 0; } //if(!WriteFile(file,data,remain,&written,NULL)) // ; //write error //if(written!=pack) // ; //write error *data=ACK; clientSocket.send(data,256); Checksum checksum; checksum.addFile(file.fileName); uint32 crc = checksum.getSum(); if(file.filecrc != crc) { //int ii = 0; } //if(calc_crc(file)!=info.crc) // ; //transfeer error } outFile.close(); } } } } }}//end namespace