fix for server on local host (for server list)

This commit is contained in:
Volker Fischer 2011-04-21 18:41:07 +00:00
parent 22591a4aae
commit 3a1c4510fa

View file

@ -1,258 +1,271 @@
/******************************************************************************\ /******************************************************************************\
* Copyright (c) 2004-2011 * Copyright (c) 2004-2011
* *
* Author(s): * Author(s):
* Volker Fischer * Volker Fischer
* *
****************************************************************************** ******************************************************************************
* *
* This program is free software; you can redistribute it and/or modify it under * This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software * 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 * Foundation; either version 2 of the License, or (at your option) any later
* version. * version.
* *
* This program is distributed in the hope that it will be useful, but WITHOUT * This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details. * details.
* *
* You should have received a copy of the GNU General Public License along with * You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., * this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
\******************************************************************************/ \******************************************************************************/
#include "serverlist.h" #include "serverlist.h"
/* Implementation *************************************************************/ /* Implementation *************************************************************/
CServerListManager::CServerListManager ( const QString& sNCentServAddr, CServerListManager::CServerListManager ( const QString& sNCentServAddr,
CProtocol* pNConLProt ) CProtocol* pNConLProt )
: strCentralServerAddress ( sNCentServAddr ), : strCentralServerAddress ( sNCentServAddr ),
pConnLessProtocol ( pNConLProt ) pConnLessProtocol ( pNConLProt )
{ {
// per definition: If the central server address is empty, the server list // per definition: If the central server address is empty, the server list
// is disabled. // is disabled.
// per definition: If we are in server mode and the central server address // per definition: If we are in server mode and the central server address
// is the localhost address, we are in central server mode. For the central // is the localhost address, we are in central server mode. For the central
// server, the server list is always enabled. // server, the server list is always enabled.
if ( !strCentralServerAddress.isEmpty() ) if ( !strCentralServerAddress.isEmpty() )
{ {
bIsCentralServer = bIsCentralServer =
( !strCentralServerAddress.toLower().compare ( "localhost" ) || ( !strCentralServerAddress.toLower().compare ( "localhost" ) ||
!strCentralServerAddress.compare ( "127.0.0.1" ) ); !strCentralServerAddress.compare ( "127.0.0.1" ) );
bEnabled = true; bEnabled = true;
} }
else else
{ {
bIsCentralServer = false; bIsCentralServer = false;
bEnabled = true; bEnabled = true;
} }
// per definition, the very first entry is this server and this entry will // per definition, the very first entry is this server and this entry will
// never be deleted // never be deleted
ServerList.clear(); ServerList.clear();
// per definition the client substitudes the IP address of the central server // per definition the client substitudes the IP address of the central server
// itself for his server list // itself for his server list
ServerList.append ( CServerListEntry ( ServerList.append ( CServerListEntry (
CHostAddress(), CHostAddress(),
"Master Server", // TEST "Master Server", // TEST
"", "",
QLocale::Germany, // TEST QLocale::Germany, // TEST
"Munich", // TEST "Munich", // TEST
0, // will be updated later 0, // will be updated later
USED_NUM_CHANNELS, USED_NUM_CHANNELS,
true ) ); // TEST true ) ); // TEST
// Connections ------------------------------------------------------------- // Connections -------------------------------------------------------------
QObject::connect ( &TimerPollList, SIGNAL ( timeout() ), QObject::connect ( &TimerPollList, SIGNAL ( timeout() ),
this, SLOT ( OnTimerPollList() ) ); this, SLOT ( OnTimerPollList() ) );
QObject::connect ( &TimerRegistering, SIGNAL ( timeout() ), QObject::connect ( &TimerRegistering, SIGNAL ( timeout() ),
this, SLOT ( OnTimerRegistering() ) ); this, SLOT ( OnTimerRegistering() ) );
} }
void CServerListManager::SetEnabled ( const bool bState ) void CServerListManager::SetEnabled ( const bool bState )
{ {
QMutexLocker locker ( &Mutex ); QMutexLocker locker ( &Mutex );
bEnabled = bState; bEnabled = bState;
if ( bEnabled ) if ( bEnabled )
{ {
if ( bIsCentralServer ) if ( bIsCentralServer )
{ {
// start timer for polling the server list if enabled // start timer for polling the server list if enabled
// 1 minute = 60 * 1000 ms // 1 minute = 60 * 1000 ms
TimerPollList.start ( SERVLIST_POLL_TIME_MINUTES * 60000 ); TimerPollList.start ( SERVLIST_POLL_TIME_MINUTES * 60000 );
} }
else else
{ {
// initiate registration right away so that we do not have to wait // initiate registration right away so that we do not have to wait
// for the first time out of the timer until the slave server gets // for the first time out of the timer until the slave server gets
// registered at the central server, note that we have to unlock // registered at the central server, note that we have to unlock
// the mutex before calling the function since inside this function // the mutex before calling the function since inside this function
// the mutex is locked, too // the mutex is locked, too
locker.unlock(); locker.unlock();
{ {
OnTimerRegistering(); OnTimerRegistering();
} }
locker.relock(); locker.relock();
// start timer for registering this server at the central server // start timer for registering this server at the central server
// 1 minute = 60 * 1000 ms // 1 minute = 60 * 1000 ms
TimerRegistering.start ( SERVLIST_REGIST_INTERV_MINUTES * 60000 ); TimerRegistering.start ( SERVLIST_REGIST_INTERV_MINUTES * 60000 );
} }
} }
else else
{ {
// disable service -> stop timer // disable service -> stop timer
if ( bIsCentralServer ) if ( bIsCentralServer )
{ {
TimerPollList.stop(); TimerPollList.stop();
} }
else else
{ {
TimerRegistering.stop(); TimerRegistering.stop();
} }
} }
} }
/* Central server functionality ***********************************************/ /* Central server functionality ***********************************************/
void CServerListManager::OnTimerPollList() void CServerListManager::OnTimerPollList()
{ {
QMutexLocker locker ( &Mutex ); QMutexLocker locker ( &Mutex );
// check all list entries except of the very first one (which is the central // check all list entries except of the very first one (which is the central
// server entry) if they are still valid // server entry) if they are still valid
for ( int iIdx = 1; iIdx < ServerList.size(); iIdx++ ) for ( int iIdx = 1; iIdx < ServerList.size(); iIdx++ )
{ {
// 1 minute = 60 * 1000 ms // 1 minute = 60 * 1000 ms
if ( ServerList[iIdx].RegisterTime.elapsed() > if ( ServerList[iIdx].RegisterTime.elapsed() >
( SERVLIST_TIME_OUT_MINUTES * 60000 ) ) ( SERVLIST_TIME_OUT_MINUTES * 60000 ) )
{ {
// remove this list entry // remove this list entry
ServerList.removeAt ( iIdx ); ServerList.removeAt ( iIdx );
} }
} }
} }
void CServerListManager::RegisterServer ( const CHostAddress& InetAddr, void CServerListManager::RegisterServer ( const CHostAddress& InetAddr,
const CServerCoreInfo& ServerInfo ) const CServerCoreInfo& ServerInfo )
{ {
QMutexLocker locker ( &Mutex ); QMutexLocker locker ( &Mutex );
if ( bIsCentralServer && bEnabled ) if ( bIsCentralServer && bEnabled )
{ {
const int iCurServerListSize = ServerList.size(); const int iCurServerListSize = ServerList.size();
// check for maximum allowed number of servers in the server list // check for maximum allowed number of servers in the server list
if ( iCurServerListSize < MAX_NUM_SERVERS_IN_SERVER_LIST ) if ( iCurServerListSize < MAX_NUM_SERVERS_IN_SERVER_LIST )
{ {
// define invalid index used as a flag // define invalid index used as a flag
const int ciInvalidIdx = -1; const int ciInvalidIdx = -1;
// Check if server is already registered. Use IP number and port // Check if server is already registered. Use IP number and port
// number to fully identify a server. The very first list entry must // number to fully identify a server. The very first list entry must
// not be checked since this is per definition the central server // not be checked since this is per definition the central server
// (i.e., this server) // (i.e., this server)
int iSelIdx = ciInvalidIdx; // initialize with an illegal value int iSelIdx = ciInvalidIdx; // initialize with an illegal value
for ( int iIdx = 1; iIdx < iCurServerListSize; iIdx++ ) for ( int iIdx = 1; iIdx < iCurServerListSize; iIdx++ )
{ {
if ( ServerList[iIdx].HostAddr == InetAddr ) if ( ServerList[iIdx].HostAddr == InetAddr )
{ {
// store entry index // store entry index
iSelIdx = iIdx; iSelIdx = iIdx;
// entry found, leave for-loop // entry found, leave for-loop
continue; continue;
} }
} }
// if server is not yet registered, we have to create a new entry // if server is not yet registered, we have to create a new entry
if ( iSelIdx == ciInvalidIdx ) if ( iSelIdx == ciInvalidIdx )
{ {
// create a new server list entry and init with received data // create a new server list entry and init with received data
ServerList.append ( CServerListEntry ( InetAddr, ServerInfo ) ); ServerList.append ( CServerListEntry ( InetAddr, ServerInfo ) );
} }
else else
{ {
// update all data and call update registration function // update all data and call update registration function
ServerList[iSelIdx].strName = ServerInfo.strName; ServerList[iSelIdx].strName = ServerInfo.strName;
ServerList[iSelIdx].strTopic = ServerInfo.strTopic; ServerList[iSelIdx].strTopic = ServerInfo.strTopic;
ServerList[iSelIdx].eCountry = ServerInfo.eCountry; ServerList[iSelIdx].eCountry = ServerInfo.eCountry;
ServerList[iSelIdx].strCity = ServerInfo.strCity; ServerList[iSelIdx].strCity = ServerInfo.strCity;
ServerList[iSelIdx].iNumClients = ServerInfo.iNumClients; ServerList[iSelIdx].iNumClients = ServerInfo.iNumClients;
ServerList[iSelIdx].iMaxNumClients = ServerInfo.iMaxNumClients; ServerList[iSelIdx].iMaxNumClients = ServerInfo.iMaxNumClients;
ServerList[iSelIdx].bPermanentOnline = ServerInfo.bPermanentOnline; ServerList[iSelIdx].bPermanentOnline = ServerInfo.bPermanentOnline;
ServerList[iSelIdx].UpdateRegistration(); ServerList[iSelIdx].UpdateRegistration();
} }
} }
} }
} }
void CServerListManager::QueryServerList ( const CHostAddress& InetAddr ) void CServerListManager::QueryServerList ( const CHostAddress& InetAddr )
{ {
QMutexLocker locker ( &Mutex ); QMutexLocker locker ( &Mutex );
if ( bIsCentralServer && bEnabled ) if ( bIsCentralServer && bEnabled )
{ {
const int iCurServerListSize = ServerList.size(); const int iCurServerListSize = ServerList.size();
// allocate memory for the entire list // allocate memory for the entire list
CVector<CServerInfo> vecServerInfo ( iCurServerListSize ); CVector<CServerInfo> vecServerInfo ( iCurServerListSize );
// copy the list (we have to copy it since the message requires // copy the list (we have to copy it since the message requires
// a vector but the list is actually stored in a QList object and // a vector but the list is actually stored in a QList object and
// not in a vector object // not in a vector object
for ( int iIdx = 0; iIdx < iCurServerListSize; iIdx++ ) for ( int iIdx = 0; iIdx < iCurServerListSize; iIdx++ )
{ {
// copy list item // copy list item
vecServerInfo[iIdx] = ServerList[iIdx]; vecServerInfo[iIdx] = ServerList[iIdx];
// create "send empty message" for all registered servers (except // check if the address of the client which is requesting the list
// of the very first list entry since this is this server (central // is the same address as one server in the list -> in this case
// server) per definition) // he has to connect to the local host address, unfortunately, the
if ( iIdx > 0 ) // port number is not known (because of NAT port translating) so we
{ // assume that it is the default llcon port number
pConnLessProtocol->CreateCLSendEmptyMesMes ( if ( vecServerInfo[iIdx].HostAddr == InetAddr )
vecServerInfo[iIdx].HostAddr, {
InetAddr ); vecServerInfo[iIdx].HostAddr.InetAddr.
} setAddress ( QHostAddress::LocalHost );
}
vecServerInfo[iIdx].HostAddr.iPort = LLCON_DEFAULT_PORT_NUMBER;
// send the server list to the client }
pConnLessProtocol->CreateCLServerListMes ( InetAddr, vecServerInfo );
} // create "send empty message" for all registered servers (except
} // of the very first list entry since this is this server (central
// server) per definition)
if ( iIdx > 0 )
/* Slave server functionality *************************************************/ {
void CServerListManager::OnTimerRegistering() pConnLessProtocol->CreateCLSendEmptyMesMes (
{ vecServerInfo[iIdx].HostAddr,
// we need the lock since the user might change the server properties at InetAddr );
// any time }
QMutexLocker locker ( &Mutex ); }
if ( !bIsCentralServer && bEnabled ) // send the server list to the client
{ pConnLessProtocol->CreateCLServerListMes ( InetAddr, vecServerInfo );
// For the slave server, the slave server properties are store in the }
// very first item in the server list (which is actually no server list }
// but just one item long for the slave server).
// Note that we always have to parse the server address again since if
// it is an URL of a dynamic IP address, the IP address might have /* Slave server functionality *************************************************/
// changed in the meanwhile. void CServerListManager::OnTimerRegistering()
CHostAddress HostAddress; {
if ( LlconNetwUtil().ParseNetworkAddress ( strCentralServerAddress, // we need the lock since the user might change the server properties at
HostAddress ) ) // any time
{ QMutexLocker locker ( &Mutex );
pConnLessProtocol->CreateCLRegisterServerMes ( HostAddress,
ServerList[0] ); if ( !bIsCentralServer && bEnabled )
} {
} // For the slave server, the slave server properties are store in the
} // very first item in the server list (which is actually no server list
// but just one item long for the slave server).
// Note that we always have to parse the server address again since if
// it is an URL of a dynamic IP address, the IP address might have
// changed in the meanwhile.
CHostAddress HostAddress;
if ( LlconNetwUtil().ParseNetworkAddress ( strCentralServerAddress,
HostAddress ) )
{
pConnLessProtocol->CreateCLRegisterServerMes ( HostAddress,
ServerList[0] );
}
}
}