diff --git a/source/glest_game/main/main.cpp b/source/glest_game/main/main.cpp index 4b58c612e..ed6efe558 100644 --- a/source/glest_game/main/main.cpp +++ b/source/glest_game/main/main.cpp @@ -350,6 +350,9 @@ int glestMain(int argc, char** argv){ MeshCallbackTeamColor::noTeamColors = true; } + //float pingTime = Socket::getAveragePingMS("soft-haus.com"); + //printf("Ping time = %f\n",pingTime); + program= new Program(); SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); diff --git a/source/glest_game/menu/menu_state_connected_game.cpp b/source/glest_game/menu/menu_state_connected_game.cpp index 5f215f0de..105837ac5 100644 --- a/source/glest_game/menu/menu_state_connected_game.cpp +++ b/source/glest_game/menu/menu_state_connected_game.cpp @@ -434,7 +434,11 @@ void MenuStateConnectedGame::update() label += " - data synch is ok"; } - labelStatus.setText(label); + float pingTime = clientInterface->getThreadedPingMS(clientInterface->getServerIpAddress().c_str()); + char szBuf[1024]=""; + sprintf(szBuf,"%s, ping = %.2fms",label.c_str(),pingTime); + + labelStatus.setText(szBuf); } else { @@ -471,7 +475,11 @@ void MenuStateConnectedGame::update() label += " - data synch is ok"; } - labelStatus.setText(label); + float pingTime = clientInterface->getThreadedPingMS(clientInterface->getServerIpAddress().c_str()); + char szBuf[1024]=""; + sprintf(szBuf,"%s, ping = %.2fms",label.c_str(),pingTime); + + labelStatus.setText(szBuf); } } else diff --git a/source/glest_game/menu/menu_state_custom_game.cpp b/source/glest_game/menu/menu_state_custom_game.cpp index bce6cf924..bd5e86cbc 100644 --- a/source/glest_game/menu/menu_state_custom_game.cpp +++ b/source/glest_game/menu/menu_state_custom_game.cpp @@ -793,7 +793,11 @@ void MenuStateCustomGame::update() } } - labelNetStatus[i].setText(label); + float pingTime = connectionSlot->getThreadedPingMS(connectionSlot->getIpAddress().c_str()); + char szBuf[1024]=""; + sprintf(szBuf,"%s, ping = %.2fms",label.c_str(),pingTime); + + labelNetStatus[i].setText(szBuf); } else { diff --git a/source/glest_game/menu/menu_state_masterserver.cpp b/source/glest_game/menu/menu_state_masterserver.cpp index 53b48c09a..4c0bc30a1 100644 --- a/source/glest_game/menu/menu_state_masterserver.cpp +++ b/source/glest_game/menu/menu_state_masterserver.cpp @@ -347,6 +347,13 @@ void MenuStateMasterserver::updateServerInfo() { masterServerInfo->setNetworkSlots(strToInt(serverEntities[9])); masterServerInfo->setConnectedClients(strToInt(serverEntities[10])); + //printf("Getting Ping time for host %s\n",masterServerInfo->getIpAddress().c_str()); + float pingTime = Socket::getAveragePingMS(masterServerInfo->getIpAddress().c_str(),1); + //printf("Ping time = %f\n",pingTime); + char szBuf[1024]=""; + sprintf(szBuf,"%s, ping = %.2fms",masterServerInfo->getServerTitle().c_str(),pingTime); + masterServerInfo->setServerTitle(szBuf); + serverLines.push_back(new ServerLine( masterServerInfo, i)); } } diff --git a/source/glest_game/network/client_interface.cpp b/source/glest_game/network/client_interface.cpp index 75b482340..0bc9e5aa5 100755 --- a/source/glest_game/network/client_interface.cpp +++ b/source/glest_game/network/client_interface.cpp @@ -117,6 +117,10 @@ void ClientInterface::update() chatTeamIndex= -1; } +std::string ClientInterface::getServerIpAddress() { + return this->ip.getString(); +} + void ClientInterface::updateLobby() { //clear chat variables @@ -665,8 +669,13 @@ void ClientInterface::sendTextMessage(const string &text, int teamIndex){ sendMessage(&networkMessageText); } -string ClientInterface::getNetworkStatus() const{ - return Lang::getInstance().get("Server") + ": " + serverName; +string ClientInterface::getNetworkStatus() { + std::string label = Lang::getInstance().get("Server") + ": " + serverName; + float pingTime = getThreadedPingMS(getServerIpAddress().c_str()); + char szBuf[1024]=""; + sprintf(szBuf,"%s, ping = %.2fms",label.c_str(),pingTime); + + return szBuf; } void ClientInterface::waitForMessage() diff --git a/source/glest_game/network/client_interface.h b/source/glest_game/network/client_interface.h index 4872ed510..4478929be 100644 --- a/source/glest_game/network/client_interface.h +++ b/source/glest_game/network/client_interface.h @@ -67,7 +67,7 @@ public: virtual void quitGame(bool userManuallyQuit); //misc - virtual string getNetworkStatus() const; + virtual string getNetworkStatus() ; //accessors string getServerName() const {return serverName;} @@ -86,6 +86,7 @@ public: void sendSwitchSetupRequest(string selectedFactionName, int8 currentFactionIndex, int8 toFactionIndex, int8 toTeam); virtual bool getConnectHasHandshaked() const { return gotIntro; } + std::string getServerIpAddress(); protected: diff --git a/source/glest_game/network/network_interface.cpp b/source/glest_game/network/network_interface.cpp index 9bbcae758..443ab7b5a 100644 --- a/source/glest_game/network/network_interface.cpp +++ b/source/glest_game/network/network_interface.cpp @@ -118,6 +118,24 @@ void NetworkInterface::clearChatInfo() { chatTeamIndex= -1; } +std::string NetworkInterface::getIpAddress() { + std::string result = ""; + + if(getSocket() != NULL) { + result = getSocket()->getIpAddress(); + } + return result; +} + +float NetworkInterface::getThreadedPingMS(std::string host) { + float result = -1; + + if(getSocket() != NULL) { + result = getSocket()->getThreadedPingMS(host); + } + return result; +} + // ===================================================== // class GameNetworkInterface // ===================================================== diff --git a/source/glest_game/network/network_interface.h b/source/glest_game/network/network_interface.h index c78ac3d7b..ca5822b23 100644 --- a/source/glest_game/network/network_interface.h +++ b/source/glest_game/network/network_interface.h @@ -106,6 +106,10 @@ public: void clearChatInfo(); virtual bool getConnectHasHandshaked() const= 0; + + std::string getIpAddress(); + float getThreadedPingMS(std::string host); + }; // ===================================================== @@ -138,7 +142,7 @@ public: virtual void quitGame(bool userManuallyQuit)=0; //misc - virtual string getNetworkStatus() const= 0; + virtual string getNetworkStatus() = 0; //access functions void requestCommand(const NetworkCommand *networkCommand, bool insertAtStart=false); diff --git a/source/glest_game/network/server_interface.cpp b/source/glest_game/network/server_interface.cpp index 52a49d969..6b7b30cef 100644 --- a/source/glest_game/network/server_interface.cpp +++ b/source/glest_game/network/server_interface.cpp @@ -623,11 +623,11 @@ void ServerInterface::quitGame(bool userManuallyQuit) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); } -string ServerInterface::getNetworkStatus() const{ +string ServerInterface::getNetworkStatus() { Lang &lang= Lang::getInstance(); string str; - SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); for(int i= 0; iisConnected()){ - str+= connectionSlot->getName(); + float pingTime = connectionSlot->getThreadedPingMS(connectionSlot->getIpAddress().c_str()); + char szBuf[100]=""; + sprintf(szBuf,", ping = %.2fms",pingTime); + + str+= connectionSlot->getName() + string(szBuf); } } else @@ -648,7 +652,7 @@ string ServerInterface::getNetworkStatus() const{ str+= '\n'; } - SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); return str; } diff --git a/source/glest_game/network/server_interface.h b/source/glest_game/network/server_interface.h index 8c7b68b26..0101c6cdf 100644 --- a/source/glest_game/network/server_interface.h +++ b/source/glest_game/network/server_interface.h @@ -59,7 +59,7 @@ public: virtual void quitGame(bool userManuallyQuit); //misc - virtual string getNetworkStatus() const; + virtual string getNetworkStatus() ; ServerSocket* getServerSocket() {return &serverSocket;} SwitchSetupRequest** getSwitchSetupRequests() {return &switchSetupRequests[0];} diff --git a/source/shared_lib/include/platform/posix/socket.h b/source/shared_lib/include/platform/posix/socket.h index 21141b820..30dcbbee5 100644 --- a/source/shared_lib/include/platform/posix/socket.h +++ b/source/shared_lib/include/platform/posix/socket.h @@ -20,6 +20,7 @@ #include #include #include "base_thread.h" +#include "simple_threads.h" using std::string; @@ -70,7 +71,7 @@ public: // class Socket // ===================================================== -class Socket { +class Socket : public SimpleTaskCallbackInterface { #ifdef WIN32 @@ -90,12 +91,20 @@ protected: PLATFORM_SOCKET sock; time_t lastDebugEvent; static int broadcast_portno; + std::string ipAddress; + + SimpleTaskThread *pingThread; + std::map pingCache; + time_t lastThreadedPing; + Mutex pingThreadAccessor; public: Socket(PLATFORM_SOCKET sock); Socket(); virtual ~Socket(); + virtual void simpleTask(); + static int getBroadCastPort() { return broadcast_portno; } static void setBroadCastPort(int value) { broadcast_portno = value; } static std::vector getLocalIPAddressList(); @@ -125,6 +134,12 @@ public: bool isSocketValid() const; static bool isSocketValid(const PLATFORM_SOCKET *validateSocket); + static float getAveragePingMS(std::string host, int pingCount=5); + float getThreadedPingMS(std::string host); + + virtual std::string getIpAddress(); + virtual void setIpAddress(std::string value) { ipAddress = value; } + protected: static void throwException(string str); }; diff --git a/source/shared_lib/sources/platform/posix/socket.cpp b/source/shared_lib/sources/platform/posix/socket.cpp index aed5c8f42..11f9b9f44 100644 --- a/source/shared_lib/sources/platform/posix/socket.cpp +++ b/source/shared_lib/sources/platform/posix/socket.cpp @@ -672,11 +672,13 @@ bool Socket::isSocketValid(const PLATFORM_SOCKET *validateSocket) { } Socket::Socket(PLATFORM_SOCKET sock){ + this->pingThread = NULL; this->sock= sock; } Socket::Socket() { + this->pingThread = NULL; sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(isSocketValid() == false) { @@ -684,6 +686,45 @@ Socket::Socket() } } +float Socket::getThreadedPingMS(std::string host) { + if(pingThread == NULL) { + pingThread = new SimpleTaskThread(this,0,50); + pingThread->start(); + } + + float result = -1; + if(pingCache.find(host) == pingCache.end()) { + MutexSafeWrapper safeMutex(&pingThreadAccessor); + pingCache[host]=-1; + safeMutex.ReleaseLock(); + result = getAveragePingMS(host, 1); + } + else { + MutexSafeWrapper safeMutex(&pingThreadAccessor); + result = pingCache[host]; + safeMutex.ReleaseLock(); + } + return result; +} + +void Socket::simpleTask() { + // update ping times every x seconds + const int pingFrequencySeconds = 2; + if(difftime(time(NULL),lastThreadedPing) < pingFrequencySeconds) { + return; + } + lastThreadedPing = time(NULL); + + //printf("Pinging hosts...\n"); + + for(std::map::iterator iterMap = pingCache.begin(); + iterMap != pingCache.end(); iterMap++) { + MutexSafeWrapper safeMutex(&pingThreadAccessor); + iterMap->second = getAveragePingMS(iterMap->first, 1); + safeMutex.ReleaseLock(); + } +} + Socket::~Socket() { SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] START closing socket = %d...\n",__FILE__,__FUNCTION__,sock); @@ -691,6 +732,10 @@ Socket::~Socket() disconnectSocket(); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END closing socket = %d...\n",__FILE__,__FUNCTION__,sock); + + BaseThread::shutdownAndWait(pingThread); + delete pingThread; + pingThread = NULL; } void Socket::disconnectSocket() @@ -1538,6 +1583,7 @@ Socket *ServerSocket::accept() { struct sockaddr_in cli_addr; socklen_t clilen = sizeof(cli_addr); + char client_host[100]=""; PLATFORM_SOCKET newSock= ::accept(sock, (struct sockaddr *) &cli_addr, &clilen); if(isSocketValid(&newSock) == false) { @@ -1553,11 +1599,12 @@ Socket *ServerSocket::accept() } else { - char client_host[100]=""; sprintf(client_host, "%s",inet_ntoa(cli_addr.sin_addr)); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] got connection, newSock = %d client_host [%s]\n",__FILE__,__FUNCTION__,__LINE__,newSock,client_host); } - return new Socket(newSock); + Socket *result = new Socket(newSock); + result->setIpAddress(client_host); + return result; } BroadCastSocketThread::BroadCastSocketThread() : BaseThread() { @@ -1703,5 +1750,91 @@ void BroadCastSocketThread::execute() { SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } +float Socket::getAveragePingMS(std::string host, int pingCount) { + double result = -1; + + const bool debugPingOutput = false; + char szCmd[1024]=""; +#ifdef WIN32 + sprintf(szCmd,"ping -n %d %s",pingCount,host.c_str()); +#else + sprintf(szCmd,"ping -c %d %s",pingCount,host.c_str()); +#endif + if(szCmd[0] != '\0') { + FILE *ping= popen(szCmd, "r"); + if (ping != NULL){ + char buf[4000]=""; + int bufferPos = 0; + for(;feof(ping) == false;) { + char *data = fgets(&buf[bufferPos], 256, ping); + bufferPos = strlen(buf); + } + pclose(ping); + + if(debugPingOutput) printf("Running cmd [%s] got [%s]\n",szCmd,buf); + + // Linux + //softcoder@softhauslinux:~/Code/megaglest/trunk/mk/linux$ ping -c 5 soft-haus.com + //PING soft-haus.com (65.254.250.110) 56(84) bytes of data. + //64 bytes from 65-254-250-110.yourhostingaccount.com (65.254.250.110): icmp_seq=1 ttl=242 time=133 ms + //64 bytes from 65-254-250-110.yourhostingaccount.com (65.254.250.110): icmp_seq=2 ttl=242 time=137 ms + // + // Windows XP + //C:\Code\megaglest\trunk\data\glest_game>ping -n 5 soft-haus.com + // + //Pinging soft-haus.com [65.254.250.110] with 32 bytes of data: + // + //Reply from 65.254.250.110: bytes=32 time=125ms TTL=242 + //Reply from 65.254.250.110: bytes=32 time=129ms TTL=242 + + std::string str = buf; + std::string::size_type ms_pos = 0; + int count = 0; + while ( ms_pos != std::string::npos) { + ms_pos = str.find("time=", ms_pos); + + if(debugPingOutput) printf("count = %d ms_pos = %d\n",count,ms_pos); + + if ( ms_pos != std::string::npos ) { + ++count; + + int endPos = str.find(" ms", ms_pos+5 ); + + if(debugPingOutput) printf("count = %d endPos = %d\n",count,endPos); + + if(endPos == std::string::npos) { + endPos = str.find("ms ", ms_pos+5 ); + + if(debugPingOutput) printf("count = %d endPos = %d\n",count,endPos); + } + + if(endPos != std::string::npos) { + + if(count == 1) { + result = 0; + } + int startPos = ms_pos + 5; + int posLength = endPos - startPos; + if(debugPingOutput) printf("count = %d startPos = %d posLength = %d str = [%s]\n",count,startPos,posLength,str.substr(startPos, posLength).c_str()); + + float pingMS = strToFloat(str.substr(startPos, posLength)); + result += pingMS; + } + + ms_pos += 5; // start next search after this "time=" + } + } + + if(result > 0 && count > 1) { + result /= count; + } + } + } + return result; +} + +std::string Socket::getIpAddress() { + return ipAddress; +} }}//end namespace