From 7d9164ad31727f1a47fab6f8f4cce11f9685a3f6 Mon Sep 17 00:00:00 2001 From: Peter L Jones Date: Sun, 20 Jun 2021 14:45:21 +0100 Subject: [PATCH] Server list persistence for directory servers with --directoryfile command line option --- src/main.cpp | 60 ++++++++- src/server.cpp | 10 +- src/server.h | 1 + src/serverlist.cpp | 309 ++++++++++++++++++++++++++++++++++----------- src/serverlist.h | 96 ++++++++------ 5 files changed, 361 insertions(+), 115 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index cf39461ad7..ab0deb4acd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -92,6 +92,7 @@ int main ( int argc, char** argv ) QString strLoggingFileName = ""; QString strRecordingDirName = ""; QString strCentralServer = ""; + QString strServerListFileName = ""; QString strServerInfo = ""; QString strServerPublicIP = ""; QString strServerBindIP = ""; @@ -215,6 +216,21 @@ int main ( int argc, char** argv ) continue; } + // Directory file ------------------------------------------------------ + if ( GetStringArgument ( argc, + argv, + i, + "--directoryfile", // no short form + "--directoryfile", + strArgument ) ) + { + strServerListFileName = strArgument; + qInfo() << qUtf8Printable ( QString ( "- directory server persistence file: %1" ).arg ( strServerListFileName ) ); + CommandLineOptions << "--directoryfile"; + ServerOnlyOptions << "--directoryfile"; + continue; + } + // Server list filter -------------------------------------------------- if ( GetStringArgument ( argc, argv, i, "-f", "--listfilter", strArgument ) ) { @@ -587,6 +603,12 @@ int main ( int argc, char** argv ) { // per definition, we must be a headless server and ignoring inifile, so we have all the information + if ( !strServerListFileName.isEmpty() ) + { + qWarning() << "Server list persistence file will only take effect when running as a directory server."; + strServerListFileName = ""; + } + if ( !strServerListFilter.isEmpty() ) { qWarning() << "Server list filter will only take effect when running as a directory server."; @@ -606,14 +628,48 @@ int main ( int argc, char** argv ) // if we are not headless, certain checks cannot be made, as the inifile state is not yet known if ( !bUseGUI && strCentralServer.compare ( "localhost", Qt::CaseInsensitive ) != 0 && strCentralServer.compare ( "127.0.0.1" ) != 0 ) { + if ( !strServerListFileName.isEmpty() ) + { + qWarning() << "Server list persistence file will only take effect when running as a directory server."; + strServerListFileName = ""; + } + if ( !strServerListFilter.isEmpty() ) { qWarning() << "Server list filter will only take effect when running as a directory server."; - strServerListFilter = ""; + strServerListFileName = ""; } } else { + if ( !strServerListFileName.isEmpty() ) + { + QFileInfo serverListFileInfo ( strServerListFileName ); + if ( !serverListFileInfo.exists() ) + { + QFile strServerListFile ( strServerListFileName ); + if ( !strServerListFile.open ( QFile::OpenModeFlag::ReadWrite ) ) + { + qWarning() << qUtf8Printable ( + QString ( "Cannot create %1 for reading and writing. Please check permissions." ).arg ( strServerListFileName ) ); + strServerListFileName = ""; + } + } + else if ( !serverListFileInfo.isFile() ) + { + qWarning() << qUtf8Printable ( + QString ( "Server list file %1 must be a plain file. Please check the name." ).arg ( strServerListFileName ) ); + strServerListFileName = ""; + } + else if ( !serverListFileInfo.isReadable() || !serverListFileInfo.isWritable() ) + { + qWarning() << qUtf8Printable ( + QString ( "Server list file %1 must be readable and writeable. Please check the permissions." ) + .arg ( strServerListFileName ) ); + strServerListFileName = ""; + } + } + if ( !strServerListFilter.isEmpty() ) { QStringList slWhitelistAddresses = strServerListFilter.split ( ";" ); @@ -779,6 +835,7 @@ int main ( int argc, char** argv ) iQosNumber, strHTMLStatusFileName, strCentralServer, + strServerListFileName, strServerInfo, strServerPublicIP, strServerListFilter, @@ -885,6 +942,7 @@ QString UsageArguments ( char** argv ) " -d, --discononquit disconnect all clients on quit\n" " -e, --directoryserver address of the directory server with which to register\n" " (or 'localhost' to host a server list on this server)\n" + " --directoryfile enable server list persistence, set file name\n" " -f, --listfilter server list whitelist filter. Format:\n" " [IP address 1];[IP address 2];[IP address 3]; ...\n" " -F, --fastupdate use 64 samples frame size mode\n" diff --git a/src/server.cpp b/src/server.cpp index 21fe46f0b2..579891f9f0 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -219,6 +219,7 @@ CServer::CServer ( const int iNewMaxNumChan, const quint16 iQosNumber, const QString& strHTMLStatusFileName, const QString& strCentralServer, + const QString& strServerListFileName, const QString& strServerInfo, const QString& strServerListFilter, const QString& strServerPublicIP, @@ -239,7 +240,14 @@ CServer::CServer ( const int iNewMaxNumChan, bWriteStatusHTMLFile ( false ), strServerHTMLFileListName ( strHTMLStatusFileName ), HighPrecisionTimer ( bNUseDoubleSystemFrameSize ), - ServerListManager ( iPortNumber, strCentralServer, strServerInfo, strServerPublicIP, strServerListFilter, iNewMaxNumChan, &ConnLessProtocol ), + ServerListManager ( iPortNumber, + strCentralServer, + strServerListFileName, + strServerInfo, + strServerPublicIP, + strServerListFilter, + iNewMaxNumChan, + &ConnLessProtocol ), JamController ( this ), bDisableRecording ( bDisableRecording ), bAutoRunMinimized ( false ), diff --git a/src/server.h b/src/server.h index 749694bb4f..35fe74522d 100644 --- a/src/server.h +++ b/src/server.h @@ -159,6 +159,7 @@ class CServer : public QObject, public CServerSlots const quint16 iQosNumber, const QString& strHTMLStatusFileName, const QString& strCentralServer, + const QString& strServerListFileName, const QString& strServerInfo, const QString& strServerListFilter, const QString& strServerPublicIP, diff --git a/src/serverlist.cpp b/src/serverlist.cpp index 97cb1e53e5..86cf093b8c 100644 --- a/src/serverlist.cpp +++ b/src/serverlist.cpp @@ -25,20 +25,87 @@ #include "serverlist.h" /* Implementation *************************************************************/ + +// --- CServerListEntry --- +CServerListEntry CServerListEntry::parse ( QString strHAddr, + QString strLHAddr, + QString sName, + QString sCity, + QString strCountry, + QString strNumClients, + bool isPermanent ) +{ + CHostAddress haServerHostAddr; + NetworkUtil::ParseNetworkAddress ( strHAddr, haServerHostAddr ); + if ( CHostAddress() == haServerHostAddr ) + { + // do not proceed without server host address! + return CServerListEntry(); + } + + CHostAddress haServerLocalAddr; + NetworkUtil::ParseNetworkAddress ( strLHAddr, haServerLocalAddr ); + if ( haServerLocalAddr.iPort == 0 ) + { + haServerLocalAddr.iPort = haServerHostAddr.iPort; + } + + // Capture parsing success of integers + bool ok; + + QLocale::Country lcCountry = QLocale::AnyCountry; + int iCountry = strCountry.trimmed().toInt ( &ok ); + if ( ok && iCountry >= 0 && iCountry <= QLocale::LastCountry ) + { + lcCountry = static_cast ( iCountry ); + } + + int iNumClients = strNumClients.trimmed().toInt ( &ok ); + if ( !ok ) + { + iNumClients = 10; + } + + return CServerListEntry ( haServerHostAddr, + haServerLocalAddr, + CServerCoreInfo ( FromBase64ToString ( sName.trimmed().left ( MAX_LEN_SERVER_NAME ) ), + lcCountry, + FromBase64ToString ( sCity.trimmed().left ( MAX_LEN_SERVER_CITY ) ), + iNumClients, + isPermanent ) ); +} + +QString CServerListEntry::toCSV() +{ + QStringList sl; + + sl.append ( this->HostAddr.toString() ); + sl.append ( this->LHostAddr.toString() ); + sl.append ( ToBase64 ( this->strName ) ); + sl.append ( ToBase64 ( this->strCity ) ); + sl.append ( QString::number ( this->eCountry ) ); + sl.append ( QString::number ( this->iMaxNumClients ) ); + sl.append ( QString::number ( this->bPermanentOnline ) ); + + return sl.join ( ";" ); +} + +// --- CServerListManager --- CServerListManager::CServerListManager ( const quint16 iNPortNum, const QString& sNCentServAddr, + const QString& strServerListFileName, const QString& strServerInfo, const QString& strServerListFilter, const QString& strServerPublicIP, const int iNumChannels, CProtocol* pNConLProt ) : eCentralServerAddressType ( AT_CUSTOM ), // must be AT_CUSTOM for the "no GUI" case - strMinServerVersion ( "" ), // disable version check with empty version - pConnLessProtocol ( pNConLProt ), eSvrRegStatus ( SRS_UNREGISTERED ), + strMinServerVersion ( "" ), // disable version check with empty version + pConnLessProtocol ( pNConLProt ), iSvrRegRetries ( 0 ) { - // set the directory server address + // set the directory server address (also bIsCentralServer) SetCentralServerAddress ( sNCentServAddr ); // set the server internal address, including internal port number @@ -69,20 +136,15 @@ CServerListManager::CServerListManager ( const quint16 iNPortNum, iServInfoNumSplitItems = slServInfoSeparateParams.count(); } - // per definition, the very first entry is this server and this entry will - // never be deleted - ServerList.clear(); - // Init server list entry (server info for this server) with defaults. Per // definition the client substitutes the IP address of the directory server - // itself for his server list. If we are the directory server, we assume that - // we have a permanent server. + // itself for his server list. If we are a directory server, we assume that + // we are a permanent server. CServerListEntry - ThisServerListEntry ( CHostAddress(), SlaveCurLocalHostAddress, "", QLocale::system().country(), "", iNumChannels, GetIsCentralServer() ); + ThisServerListEntry ( CHostAddress(), SlaveCurLocalHostAddress, "", QLocale::system().country(), "", iNumChannels, bIsCentralServer ); // parse the server info string according to definition: - // [this server name];[this server city]; ... - // [this server country as QLocale ID]; ... + // [this server name];[this server city];[this server country as QLocale ID] (; ... ignored) // per definition, we expect at least three parameters if ( iServInfoNumSplitItems >= 3 ) { @@ -93,43 +155,59 @@ CServerListManager::CServerListManager ( const quint16 iNPortNum, ThisServerListEntry.strCity = slServInfoSeparateParams[1].left ( MAX_LEN_SERVER_CITY ); // [this server country as QLocale ID] - const int iCountry = slServInfoSeparateParams[2].toInt(); - - if ( !slServInfoSeparateParams[2].isEmpty() && ( iCountry >= 0 ) && ( iCountry <= QLocale::LastCountry ) ) + bool ok; + const int iCountry = slServInfoSeparateParams[2].toInt ( &ok ); + if ( ok && iCountry >= 0 && iCountry <= QLocale::LastCountry ) { ThisServerListEntry.eCountry = static_cast ( iCountry ); } } + // per definition, the very first entry is this server and this entry will + // never be deleted + ServerList.clear(); + // per definition, the first entry in the server list is the own server ServerList.append ( ThisServerListEntry ); - // whitelist parsing - if ( !strServerListFilter.isEmpty() ) + // Clear the persistent serverlist file name + ServerListFileName.clear(); + + if ( bIsCentralServer ) { - // split the different parameter strings - QStringList slWhitelistAddresses = strServerListFilter.split ( ";" ); - QHostAddress CurWhiteListAddress; + // Load any persistent server list (create it if it is not there) + if ( !strServerListFileName.isEmpty() && ServerListFileName.isEmpty() ) + { + CentralServerLoadServerList ( strServerListFileName ); + } - for ( int iIdx = 0; iIdx < slWhitelistAddresses.size(); iIdx++ ) + // whitelist parsing + if ( !strServerListFilter.isEmpty() ) { - // check for special case: [version] - if ( ( slWhitelistAddresses.at ( iIdx ).length() > 2 ) && ( slWhitelistAddresses.at ( iIdx ).left ( 1 ) == "[" ) && - ( slWhitelistAddresses.at ( iIdx ).right ( 1 ) == "]" ) ) - { - strMinServerVersion = slWhitelistAddresses.at ( iIdx ).mid ( 1, slWhitelistAddresses.at ( iIdx ).length() - 2 ); - } - else if ( CurWhiteListAddress.setAddress ( slWhitelistAddresses.at ( iIdx ) ) ) + // split the different parameter strings + QStringList slWhitelistAddresses = strServerListFilter.split ( ";" ); + QHostAddress CurWhiteListAddress; + + for ( int iIdx = 0; iIdx < slWhitelistAddresses.size(); iIdx++ ) { - vWhiteList << CurWhiteListAddress; - qInfo() << qUtf8Printable ( QString ( "Whitelist entry added: %1" ).arg ( CurWhiteListAddress.toString() ) ); + // check for special case: [version] + if ( ( slWhitelistAddresses.at ( iIdx ).length() > 2 ) && ( slWhitelistAddresses.at ( iIdx ).left ( 1 ) == "[" ) && + ( slWhitelistAddresses.at ( iIdx ).right ( 1 ) == "]" ) ) + { + strMinServerVersion = slWhitelistAddresses.at ( iIdx ).mid ( 1, slWhitelistAddresses.at ( iIdx ).length() - 2 ); + } + else if ( CurWhiteListAddress.setAddress ( slWhitelistAddresses.at ( iIdx ) ) ) + { + vWhiteList << CurWhiteListAddress; + qInfo() << qUtf8Printable ( QString ( "Whitelist entry added: %1" ).arg ( CurWhiteListAddress.toString() ) ); + } } } } // for slave servers start the one shot timer for determining if it is a // permanent server - if ( !GetIsCentralServer() ) + if ( !bIsCentralServer ) { // 1 minute = 60 * 1000 ms QTimer::singleShot ( SERVLIST_TIME_PERMSERV_MINUTES * 60000, this, SLOT ( OnTimerIsPermanent() ) ); @@ -149,6 +227,8 @@ CServerListManager::CServerListManager ( const quint16 iNPortNum, QObject::connect ( &TimerRegistering, &QTimer::timeout, this, &CServerListManager::OnTimerRegistering ); QObject::connect ( &TimerCLRegisterServerResp, &QTimer::timeout, this, &CServerListManager::OnTimerCLRegisterServerResp ); + + QObject::connect ( QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &CServerListManager::OnAboutToQuit ); } void CServerListManager::SetCentralServerAddress ( const QString sNCentServAddr ) @@ -170,10 +250,7 @@ void CServerListManager::SetCentralServerAddress ( const QString sNCentServAddr // now save the new name strCentralServerAddress = sNCentServAddr; - // per definition: If we are in server mode and the directory server address - // is the localhost address, and set to Custom, we are in directory server mode. - bIsCentralServer = ( ( !strCentralServerAddress.toLower().compare ( "localhost" ) || !strCentralServerAddress.compare ( "127.0.0.1" ) ) && - ( eCentralServerAddressType == AT_CUSTOM ) ); + SetCentralServerState(); } void CServerListManager::SetCentralServerAddressType ( const ECSAddType eNCSAT ) @@ -189,10 +266,21 @@ void CServerListManager::SetCentralServerAddressType ( const ECSAddType eNCSAT ) // now update the server type eCentralServerAddressType = eNCSAT; + SetCentralServerState(); +} + +void CServerListManager::SetCentralServerState() +{ // per definition: If we are in server mode and the directory server address // is the localhost address, and set to Custom, we are in directory server mode. - bIsCentralServer = ( ( !strCentralServerAddress.toLower().compare ( "localhost" ) || !strCentralServerAddress.compare ( "127.0.0.1" ) ) && - ( eCentralServerAddressType == AT_CUSTOM ) ); + bool bNCentralServer = + ( ( !strCentralServerAddress.compare ( "localhost", Qt::CaseInsensitive ) || !strCentralServerAddress.compare ( "127.0.0.1" ) ) && + ( eCentralServerAddressType == AT_CUSTOM ) ); + if ( bIsCentralServer != bNCentralServer ) + { + bIsCentralServer = bNCentralServer; + qInfo() << ( bIsCentralServer ? "Now a directory server" : "No longer a directory server" ); + } } void CServerListManager::Update() @@ -281,11 +369,8 @@ void CServerListManager::OnTimerPollList() QMutexLocker locker ( &Mutex ); - // Check all list entries except of the very first one (which is the directory - // server entry) if they are still valid. - // Note that we have to use "ServerList.size()" function in the for loop - // since we may remove elements from the server list inside the for loop. - for ( int iIdx = 1; iIdx < ServerList.size(); ) + // Check all list entries are still valid (omitting the directory server itself) + for ( int iIdx = ServerList.size() - 1; iIdx > 0; iIdx-- ) { // 1 minute = 60 * 1000 ms if ( ServerList[iIdx].RegisterTime.elapsed() > ( SERVLIST_TIME_OUT_MINUTES * 60000 ) ) @@ -294,11 +379,6 @@ void CServerListManager::OnTimerPollList() vecRemovedHostAddr.Add ( ServerList[iIdx].HostAddr ); ServerList.removeAt ( iIdx ); } - else - { - // move to the next entry (only on else) - iIdx++; - } } locker.unlock(); @@ -353,19 +433,7 @@ void CServerListManager::CentralServerRegisterServer ( const CHostAddress& In // Check if server is already registered. // The very first list entry must not be checked since // this is per definition the directory server (i.e., this server) - int iSelIdx = INVALID_INDEX; // initialize with an illegal value - - for ( int iIdx = 1; iIdx < iCurServerListSize; iIdx++ ) - { - if ( ServerList[iIdx].HostAddr == InetAddr ) - { - // store entry index - iSelIdx = iIdx; - - // entry found, leave for-loop - continue; - } - } + int iSelIdx = IndexOf ( InetAddr ); // if server is not yet registered, we have to create a new entry if ( iSelIdx == INVALID_INDEX ) @@ -405,24 +473,13 @@ void CServerListManager::CentralServerUnregisterServer ( const CHostAddress& Ine QMutexLocker locker ( &Mutex ); - const int iCurServerListSize = ServerList.size(); - // Find the server to unregister in the list. The very first list entry - // must not be checked since this is per definition the directory server + // must not be removed since this is per definition the directory server // (i.e., this server). - for ( int iIdx = 1; iIdx < iCurServerListSize; iIdx++ ) + int iIdx = IndexOf ( InetAddr ); + if ( iIdx > 0 ) { - if ( ServerList[iIdx].HostAddr == InetAddr ) - { - // remove this list entry - ServerList.removeAt ( iIdx ); - - // entry found, leave for-loop (it is important to exit the - // for loop since when we remove an item from the server list, - // "iCurServerListSize" is not correct anymore and we could get - // a segmentation fault) - break; - } + ServerList.removeAt ( iIdx ); } } } @@ -469,6 +526,7 @@ void CServerListManager::CentralServerQueryServerList ( const CHostAddress& Inet // servers behind a NAT and dealing with external, public // clients. vecServerInfo[iIdx].HostAddr = ServerList[iIdx].LHostAddr; + // ?? Shouldn't this send the ping, as below ?? } else { @@ -490,6 +548,107 @@ void CServerListManager::CentralServerQueryServerList ( const CHostAddress& Inet } } +int CServerListManager::IndexOf ( CHostAddress haSearchTerm ) +{ + // Find the server in the list. The very first list entry + // per definition is the directory server + // (i.e., this server). + for ( int iIdx = ServerList.size() - 1; iIdx > 0; iIdx-- ) + { + if ( ServerList[iIdx].HostAddr == haSearchTerm ) + { + return iIdx; + } + } + return INVALID_INDEX; +} + +void CServerListManager::CentralServerLoadServerList ( const QString strServerList ) +{ + QFile file ( strServerList ); + + if ( !file.open ( QIODevice::ReadWrite | QIODevice::Text ) ) + { + qWarning() << qUtf8Printable ( + QString ( "Could not open '%1' for read/write. Please check that Jamulus has permission (and that there is free space)." ) + .arg ( ServerListFileName ) ); + return; + } + + // use entire file content for the persistent server list + // and remember it for later writing + qInfo() << "Setting persistent server list file:" << strServerList; + ServerListFileName = strServerList; + CHostAddress haServerHostAddr; + + QTextStream in ( &file ); + while ( !in.atEnd() ) + { + QString line = in.readLine(); + QStringList slLine = line.split ( ";" ); + if ( slLine.count() != 7 ) + { + qWarning() << qUtf8Printable ( QString ( "Could not parse '%1' successfully - bad line" ).arg ( line ) ); + continue; + } + + NetworkUtil::ParseNetworkAddress ( slLine[0], haServerHostAddr ); + int iIdx = IndexOf ( haServerHostAddr ); + if ( iIdx != INVALID_INDEX ) + { + qWarning() << qUtf8Printable ( QString ( "Skipping '%1' - duplicate host %2" ).arg ( line ).arg ( haServerHostAddr.toString() ) ); + continue; + } + + CServerListEntry serverListEntry = + CServerListEntry::parse ( slLine[0], slLine[1], slLine[2], slLine[3], slLine[4], slLine[5], slLine[6].toInt() != 0 ); + + // We expect servers to have addresses... + if ( ( CHostAddress() == serverListEntry.HostAddr ) ) + { + qWarning() << qUtf8Printable ( QString ( "Could not parse '%1' successfully - invalid host" ).arg ( line ) ); + continue; + } + + qInfo() << qUtf8Printable ( QString ( "Loading registration for %1 (%2): %3" ) + .arg ( serverListEntry.HostAddr.toString() ) + .arg ( serverListEntry.LHostAddr.toString() ) + .arg ( serverListEntry.strName ) ); + ServerList.append ( serverListEntry ); + } +} + +void CServerListManager::CentralServerSaveServerList() +{ + if ( ServerListFileName.isEmpty() ) + { + return; + } + + QFile file ( ServerListFileName ); + + if ( !file.open ( QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text ) ) + { + // Not a useable file + qWarning() << QString ( tr ( "Could not write to '%1'" ) ).arg ( ServerListFileName ); + ServerListFileName.clear(); + + return; + } + + QTextStream out ( &file ); + // This loop *deliberately* omits the first element in the list + // (that's this server, which is added automatically on start up, not read) + for ( int iIdx = ServerList.size() - 1; iIdx > 0; iIdx-- ) + { + qInfo() << qUtf8Printable ( QString ( "Saving registration for %1 (%2): %3" ) + .arg ( ServerList[iIdx].HostAddr.toString() ) + .arg ( ServerList[iIdx].LHostAddr.toString() ) + .arg ( ServerList[iIdx].strName ) ); + out << ServerList[iIdx].toCSV() << "\n"; + } +} + /* Slave server functionality *************************************************/ void CServerListManager::StoreRegistrationResult ( ESvrRegResult eResult ) { diff --git a/src/serverlist.h b/src/serverlist.h index 6e635157b5..9dbaecd00b 100644 --- a/src/serverlist.h +++ b/src/serverlist.h @@ -107,9 +107,24 @@ class CServerListEntry : public CServerInfo void UpdateRegistration() { RegisterTime.start(); } -public: + static CServerListEntry parse ( QString strHAddr, + QString strLHAddr, + QString sName, + QString sCity, + QString strCountry, + QString strNumClients, + bool isPermanent ); + QString toCSV(); + // time on which the entry was registered QElapsedTimer RegisterTime; + +protected: + // Taken from src/settings.h - the same comment applies + static QString ToBase64 ( const QByteArray strIn ) { return QString::fromLatin1 ( strIn.toBase64() ); } + static QString ToBase64 ( const QString strIn ) { return ToBase64 ( strIn.toUtf8() ); } + static QByteArray FromBase64ToByteArray ( const QString strIn ) { return QByteArray::fromBase64 ( strIn.toLatin1() ); } + static QString FromBase64ToString ( const QString strIn ) { return QString::fromUtf8 ( FromBase64ToByteArray ( strIn ) ); } }; class CServerListManager : public QObject @@ -119,19 +134,30 @@ class CServerListManager : public QObject public: CServerListManager ( const quint16 iNPortNum, const QString& sNCentServAddr, + const QString& strServerListFileName, const QString& strServerInfo, const QString& strServerListFilter, const QString& strServerPublicIP, const int iNumChannels, CProtocol* pNConLProt ); - // the update has to be called if any change to the server list - // properties was done - void Update(); - void SetEnabled ( const bool bState ) { bEnabled = bState; } bool GetEnabled() const { return bEnabled; } + void SlaveServerUnregister() { SlaveServerRegisterServer ( false ); } + + // set server infos -> per definition the server info of this server is + // stored in the first entry of the list, we assume here that the first + // entry is correctly created in the constructor of the class + void SetServerName ( const QString& strNewName ) { ServerList[0].strName = strNewName; } + QString GetServerName() { return ServerList[0].strName; } + + void SetServerCity ( const QString& strNewCity ) { ServerList[0].strCity = strNewCity; } + QString GetServerCity() { return ServerList[0].strCity; } + + void SetServerCountry ( const QLocale::Country eNewCountry ) { ServerList[0].eCountry = eNewCountry; } + QLocale::Country GetServerCountry() { return ServerList[0].eCountry; } + void SetCentralServerAddress ( const QString sNCentServAddr ); QString GetCentralServerAddress() { return strCentralServerAddress; } @@ -140,76 +166,70 @@ class CServerListManager : public QObject bool GetIsCentralServer() const { return bIsCentralServer; } + ESvrRegStatus GetSvrRegStatus() { return eSvrRegStatus; } + + // the update has to be called if any change to the server list + // properties was done + void Update(); + void CentralServerRegisterServer ( const CHostAddress& InetAddr, const CHostAddress& LInetAddr, const CServerCoreInfo& ServerInfo, const QString strVersion = "" ); - void CentralServerUnregisterServer ( const CHostAddress& InetAddr ); - void CentralServerQueryServerList ( const CHostAddress& InetAddr ); - void SlaveServerUnregister() { SlaveServerRegisterServer ( false ); } - - // set server infos -> per definition the server info of this server is - // stored in the first entry of the list, we assume here that the first - // entry is correctly created in the constructor of the class - void SetServerName ( const QString& strNewName ) { ServerList[0].strName = strNewName; } - - QString GetServerName() { return ServerList[0].strName; } - - void SetServerCity ( const QString& strNewCity ) { ServerList[0].strCity = strNewCity; } - - QString GetServerCity() { return ServerList[0].strCity; } - - void SetServerCountry ( const QLocale::Country eNewCountry ) { ServerList[0].eCountry = eNewCountry; } - - QLocale::Country GetServerCountry() { return ServerList[0].eCountry; } - - ESvrRegStatus GetSvrRegStatus() { return eSvrRegStatus; } - void StoreRegistrationResult ( ESvrRegResult eStatus ); protected: + void SetCentralServerState(); + int IndexOf ( CHostAddress haSearchTerm ); + void CentralServerLoadServerList ( const QString strServerList ); + void CentralServerSaveServerList(); void SlaveServerRegisterServer ( const bool bIsRegister ); void SetSvrRegStatus ( ESvrRegStatus eNSvrRegStatus ); - QTimer TimerPollList; - QTimer TimerRegistering; - QTimer TimerPingServerInList; - QTimer TimerPingCentralServer; - QTimer TimerCLRegisterServerResp; - QMutex Mutex; + bool bEnabled; + QList ServerList; QString strCentralServerAddress; - bool bEnabled; - bool bIsCentralServer; ECSAddType eCentralServerAddressType; + bool bIsCentralServer; + + // server registration status + ESvrRegStatus eSvrRegStatus; CHostAddress SlaveCurCentServerHostAddress; CHostAddress SlaveCurLocalHostAddress; + QString ServerListFileName; + QList vWhiteList; QString strMinServerVersion; CProtocol* pConnLessProtocol; - // server registration status - ESvrRegStatus eSvrRegStatus; - // count of registration retries int iSvrRegRetries; + QTimer TimerPollList; + QTimer TimerPingServerInList; + QTimer TimerPingCentralServer; + QTimer TimerRegistering; + QTimer TimerCLRegisterServerResp; + public slots: void OnTimerPollList(); void OnTimerPingServerInList(); void OnTimerPingCentralServer(); - void OnTimerCLRegisterServerResp(); void OnTimerRegistering() { SlaveServerRegisterServer ( true ); } + void OnTimerCLRegisterServerResp(); + void OnTimerIsPermanent() { ServerList[0].bPermanentOnline = true; } + void OnAboutToQuit() { CentralServerSaveServerList(); } signals: void SvrRegStatusChanged();