Merge pull request #87 from pljones/feature/55-server-registration-status

Allow central server to confirm registration
This commit is contained in:
corrados 2020-04-18 06:51:03 +02:00 committed by GitHub
commit 9161853a9d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 288 additions and 12 deletions

View file

@ -215,6 +215,13 @@ LED bar: lbr
// defines the minimum time a server must run to be a permanent server
#define SERVLIST_TIME_PERMSERV_MINUTES 1440 // minutes, 1440 = 60 min * 24 h
// registration response timeout
#define REGISTER_SERVER_TIME_OUT_MS 500 // ms
// defines the maximum number of times to retry server registration
// when no response is received within the timeout (before reverting
// to SERVLIST_REGIST_INTERV_MINUTES)
#define REGISTER_SERVER_RETRY_LIMIT 5 // count
// length of the moving average buffer for response time measurement
#define TIME_MOV_AV_RESPONSE_SECONDS 30 // seconds

View file

@ -289,6 +289,7 @@ CONNECTION LESS MESSAGES
note: does not have any data -> n = 0
- PROTMESSID_CLM_CHANNEL_LEVEL_LIST: The channel level list
+----------------------------------+
@ -304,13 +305,32 @@ CONNECTION LESS MESSAGES
where an odd number of clients is connected, there will be four unused
upper bits in the final byte, containing 0xF (which is out of range)
the server may compute them message when any client has used
the server may compute the message when any client has used
PROTMESSID_CLM_REQ_CHANNEL_LEVEL_LIST to opt in
the server may issue to message only to a client that has used
the server should issue the message only to a client that has used
PROTMESSID_CLM_REQ_CHANNEL_LEVEL_LIST to opt in
- PROTMESSID_CLM_REGISTER_SERVER_RESP: result of registration request
+---------------+
| 1 byte status |
+---------------+
- "status":
Values of ESvrRegResult:
0 - success
1 - failed due to central server list being full
Note: the central server may send this message in response to a
PROTMESSID_CLM_REGISTER_SERVER request.
Where not received, the registering server may only retry up to
five times for one registration request at 500ms intervals.
Beyond this, it should "ping" every 15 minutes
(standard re-registration timeout).
******************************************************************************
*
* This program is free software; you can redistribute it and/or modify it under
@ -676,6 +696,10 @@ if ( rand() < ( RAND_MAX / 2 ) ) return false;
case PROTMESSID_CLM_CHANNEL_LEVEL_LIST:
bRet = EvaluateCLChannelLevelListMes ( InetAddr, vecbyMesBodyData );
break;
case PROTMESSID_CLM_REGISTER_SERVER_RESP:
bRet = EvaluateCLRegisterServerResp ( InetAddr, vecbyMesBodyData );
break;
}
}
else
@ -2090,6 +2114,39 @@ bool CProtocol::EvaluateCLChannelLevelListMes ( const CHostAddress& InetAdd
return false; // no error
}
void CProtocol::CreateCLRegisterServerResp ( const CHostAddress& InetAddr,
const ESvrRegResult eResult )
{
int iPos = 0; // init position pointer
CVector<uint8_t> vecData( 1 );
PutValOnStream ( vecData, iPos,
static_cast<uint32_t> ( eResult ), 1 );
CreateAndImmSendConLessMessage ( PROTMESSID_CLM_REGISTER_SERVER_RESP,
vecData,
InetAddr );
}
bool CProtocol::EvaluateCLRegisterServerResp ( const CHostAddress& InetAddr,
const CVector<uint8_t>& vecData )
{
int iPos = 0; // init position pointer
const int iDataLen = vecData.Size();
if ( iDataLen != 1 )
{
return true;
}
ESvrRegResult eResult = static_cast<ESvrRegResult> (
GetValFromStream ( vecData, iPos, 1 ) );
// invoke message action
emit CLRegisterServerResp ( InetAddr, eResult );
return false; // no error
}
/******************************************************************************\
* Message generation and parsing *

View file

@ -73,6 +73,7 @@
#define PROTMESSID_CLM_CONN_CLIENTS_LIST 1013 // channel infos for connected clients
#define PROTMESSID_CLM_REQ_CONN_CLIENTS_LIST 1014 // request the connected clients list
#define PROTMESSID_CLM_CHANNEL_LEVEL_LIST 1015 // channel level list
#define PROTMESSID_CLM_REGISTER_SERVER_RESP 1016 // status of server registration request
// lengths of message as defined in protocol.cpp file
#define MESS_HEADER_LENGTH_BYTE 7 // TAG (2), ID (2), cnt (1), length (2)
@ -130,6 +131,8 @@ public:
void CreateCLChannelLevelListMes ( const CHostAddress& InetAddr,
const CVector<uint16_t>& vecLevelList,
const int iNumClients );
void CreateCLRegisterServerResp ( const CHostAddress& InetAddr,
const ESvrRegResult eResult );
static bool ParseMessageFrame ( const CVector<uint8_t>& vecbyData,
const int iNumBytesIn,
@ -246,6 +249,8 @@ protected:
bool EvaluateCLReqConnClientsListMes ( const CHostAddress& InetAddr );
bool EvaluateCLChannelLevelListMes ( const CHostAddress& InetAddr,
const CVector<uint8_t>& vecData );
bool EvaluateCLRegisterServerResp ( const CHostAddress& InetAddr,
const CVector<uint8_t>& vecData );
int iOldRecID;
int iOldRecCnt;
@ -305,4 +310,6 @@ signals:
void CLReqConnClientsList ( CHostAddress InetAddr );
void CLChannelLevelListReceived ( CHostAddress InetAddr,
CVector<uint16_t> vecLevelList );
void CLRegisterServerResp ( CHostAddress InetAddr,
ESvrRegResult eStatus );
};

View file

@ -438,6 +438,10 @@ CServer::CServer ( const int iNewMaxNumChan,
SIGNAL ( CLReqServerList ( CHostAddress ) ),
this, SLOT ( OnCLReqServerList ( CHostAddress ) ) );
QObject::connect ( &ConnLessProtocol,
SIGNAL ( CLRegisterServerResp ( CHostAddress, ESvrRegResult ) ),
this, SLOT ( OnCLRegisterServerResp ( CHostAddress, ESvrRegResult ) ) );
QObject::connect ( &ConnLessProtocol,
SIGNAL ( CLSendEmptyMes ( CHostAddress ) ),
this, SLOT ( OnCLSendEmptyMes ( CHostAddress ) ) );
@ -454,6 +458,10 @@ CServer::CServer ( const int iNewMaxNumChan,
SIGNAL ( CLReqConnClientsList ( CHostAddress ) ),
this, SLOT ( OnCLReqConnClientsList ( CHostAddress ) ) );
QObject::connect ( &ServerListManager,
SIGNAL ( SvrRegStatusChanged() ),
this, SLOT ( OnSvrRegStatusChanged() ) );
// CODE TAG: MAX_NUM_CHANNELS_TAG
// make sure we have MAX_NUM_CHANNELS connections!!!
// send message

View file

@ -190,6 +190,7 @@ public:
QLocale::Country GetServerCountry()
{ return ServerListManager.GetServerCountry(); }
ESvrRegStatus GetSvrRegStatus() { return ServerListManager.GetSvrRegStatus(); }
// GUI settings ------------------------------------------------------------
void SetAutoRunMinimized ( const bool NAuRuMin ) { bAutoRunMinimized = NAuRuMin; }
@ -305,6 +306,7 @@ signals:
void Started();
void Stopped();
void ClientDisconnected ( const int iChID );
void SvrRegStatusChanged();
void AudioFrame ( const int iChID,
const QString stChName,
const CHostAddress RecHostAddr,
@ -373,6 +375,14 @@ public slots:
ServerListManager.CentralServerRegisterServer ( InetAddr, LInetAddr, ServerInfo );
}
void OnCLRegisterServerResp ( CHostAddress /* unused */,
ESvrRegResult eResult )
{
ServerListManager.StoreRegistrationResult ( eResult );
}
void OnSvrRegStatusChanged() { emit SvrRegStatusChanged(); }
void OnCLUnregisterServerReceived ( CHostAddress InetAddr )
{
ServerListManager.CentralServerUnregisterServer ( InetAddr );

View file

@ -61,15 +61,20 @@ CServerDlg::CServerDlg ( CServer* pNServP,
"Dialog:</b> If enabled, a Creative Commons Licence dialog is shown "
"each time a new user connects the server." ) );
// register server flag
chbRegisterServer->setWhatsThis ( tr ( "<b>Register Server Status:</b> If "
"the register server check box is checked, this server registers "
// Make My Server Public flag
chbRegisterServer->setWhatsThis ( tr ( "<b>Make My Server Public:</b> If "
"the Make My Server Public check box is checked, this server registers "
"itself at the central server so that all " ) + APP_NAME +
tr ( " users can see the server in the connect dialog server list and "
"connect to it. The registering of the server is renewed periodically "
"to make sure that all servers in the connect dialog server list are "
"actually available." ) );
// register server status label
lblRegSvrStatus->setWhatsThis ( tr ( "<b>Register Server Status:</b> If "
"the Make My Server Public check box is checked, this will show "
"the success of registration with the central server." ) );
// central server address
QString strCentrServAddr = tr ( "<b>Central Server Address:</b> The "
"Central server address is the IP address or URL of the central server "
@ -322,6 +327,9 @@ lvwClients->setMinimumHeight ( 140 );
QObject::connect ( pServer, SIGNAL ( Stopped() ),
this, SLOT ( OnServerStopped() ) );
QObject::connect ( pServer, SIGNAL ( SvrRegStatusChanged() ),
this, SLOT ( OnSvrRegStatusChanged() ) );
QObject::connect ( QCoreApplication::instance(), SIGNAL ( aboutToQuit() ),
this, SLOT ( OnAboutToQuit() ) );
@ -507,6 +515,8 @@ void CServerDlg::UpdateGUIDependencies()
const bool bCurUseDefCentServAddr = ( pServer->GetCentralServerAddressType() != AT_MANUAL );
const ESvrRegStatus eSvrRegStatus = pServer->GetSvrRegStatus();
// if register server is not enabled, we disable all the configuration
// controls for the server list
cbxCentServAddrType->setEnabled ( bCurSerListEnabled );
@ -534,6 +544,34 @@ void CServerDlg::UpdateGUIDependencies()
// server list is enabled and not the default address is used
edtCentralServerAddress->setEnabled (
!bCurUseDefCentServAddr && bCurSerListEnabled );
QString strStatus;
switch ( eSvrRegStatus )
{
case SRS_UNREGISTERED:
strStatus = "Unregistered";
break;
case SRS_BAD_ADDRESS:
strStatus = "Bad address";
break;
case SRS_REQUESTED:
strStatus = "Registration requested";
break;
case SRS_TIME_OUT:
strStatus = "Using longer retries";
break;
case SRS_UNKNOWN_RESP:
strStatus = "Check server version, retrying";
break;
case SRS_REGISTERED:
strStatus = "Registered";
break;
case SRS_CENTRAL_SVR_FULL:
strStatus = "Central Server full";
break;
}
lblRegSvrStatus->setText( strStatus );
}
void CServerDlg::UpdateSystemTrayIcon ( const bool bIsActive )

View file

@ -94,6 +94,7 @@ public slots:
void OnTimer();
void OnServerStarted() { UpdateSystemTrayIcon ( true ); }
void OnServerStopped() { UpdateSystemTrayIcon ( false ); }
void OnSvrRegStatusChanged() { UpdateGUIDependencies(); }
void OnSysTrayMenuOpen() { ShowWindowInForeground(); }
void OnSysTrayMenuHide() { hide(); }
void OnSysTrayMenuExit() { close(); }

View file

@ -60,6 +60,8 @@
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QCheckBox" name="chbRegisterServer">
<property name="text">
@ -67,6 +69,31 @@
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="lblRegSvrStatus">
<property name="text">
<string>STATUS</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout">
<item>

View file

@ -34,7 +34,9 @@ CServerListManager::CServerListManager ( const quint16 iNPortNum,
: iNumPredefinedServers ( 0 ),
eCentralServerAddressType ( AT_MANUAL ), // must be AT_MANUAL for the "no GUI" case
bCentServPingServerInList ( bNCentServPingServerInList ),
pConnLessProtocol ( pNConLProt )
pConnLessProtocol ( pNConLProt ),
eSvrRegStatus ( SRS_UNREGISTERED ),
iSvrRegRetries ( 0 )
{
// set the central server address
SetCentralServerAddress ( sNCentServAddr );
@ -177,6 +179,11 @@ CServerListManager::CServerListManager ( const quint16 iNPortNum,
QObject::connect ( &TimerRegistering, SIGNAL ( timeout() ),
this, SLOT ( OnTimerRegistering() ) );
TimerCLRegisterServerResp.setSingleShot ( true );
TimerCLRegisterServerResp.setInterval ( REGISTER_SERVER_TIME_OUT_MS );
QObject::connect ( &TimerCLRegisterServerResp, SIGNAL ( timeout() ),
this, SLOT ( OnTimerCLRegisterServerResp() ) );
}
void CServerListManager::SetCentralServerAddress ( const QString sNCentServAddr )
@ -239,6 +246,12 @@ void CServerListManager::Update()
}
locker.relock();
// reset the retry counter to zero because update was called
iSvrRegRetries = 0;
// start timer for registration timeout
TimerCLRegisterServerResp.start();
// start timer for registering this server at the central server
// 1 minute = 60 * 1000 ms
TimerRegistering.start ( SERVLIST_REGIST_INTERV_MINUTES * 60000 );
@ -266,6 +279,7 @@ void CServerListManager::Update()
}
else
{
TimerCLRegisterServerResp.stop();
TimerRegistering.stop();
TimerPingCentralServer.stop();
}
@ -297,7 +311,7 @@ void CServerListManager::OnTimerPollList()
// server entry) and the predefined servers 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 + iNumPredefinedServers; iIdx < ServerList.size(); iIdx++ )
for ( int iIdx = 1 + iNumPredefinedServers; iIdx < ServerList.size(); )
{
// 1 minute = 60 * 1000 ms
if ( ServerList[iIdx].RegisterTime.elapsed() >
@ -306,6 +320,11 @@ void CServerListManager::OnTimerPollList()
// remove this list entry
ServerList.removeAt ( iIdx );
}
else
{
// Move to the next entry (only on else)
iIdx++;
}
}
}
@ -346,6 +365,7 @@ void CServerListManager::CentralServerRegisterServer ( const CHostAddress& In
{
// create a new server list entry and init with received data
ServerList.append ( CServerListEntry ( InetAddr, LInetAddr, ServerInfo ) );
iSelIdx = iCurServerListSize;
}
}
else
@ -364,6 +384,10 @@ void CServerListManager::CentralServerRegisterServer ( const CHostAddress& In
ServerList[iSelIdx].UpdateRegistration();
}
}
pConnLessProtocol->CreateCLRegisterServerResp ( InetAddr, iSelIdx == ciInvalidIdx
? ESvrRegResult::SRR_CENTRAL_SVR_FULL
: ESvrRegResult::SRR_REGISTERED );
}
}
@ -452,6 +476,30 @@ void CServerListManager::CentralServerQueryServerList ( const CHostAddress& Inet
/* Slave server functionality *************************************************/
void CServerListManager::StoreRegistrationResult ( ESvrRegResult eResult )
{
// we need the lock since the user might change the server properties at
// any time so another response could arrive
QMutexLocker locker ( &Mutex );
// We got some response, so stop the retry timer
TimerCLRegisterServerResp.stop();
eSvrRegStatus = ESvrRegStatus::SRS_UNKNOWN_RESP;
switch ( eResult )
{
case ESvrRegResult::SRR_REGISTERED:
eSvrRegStatus = ESvrRegStatus::SRS_REGISTERED;
break;
case ESvrRegResult::SRR_CENTRAL_SVR_FULL:
eSvrRegStatus = ESvrRegStatus::SRS_CENTRAL_SVR_FULL;
break;
}
emit SvrRegStatusChanged();
}
void CServerListManager::OnTimerPingCentralServer()
{
QMutexLocker locker ( &Mutex );
@ -465,6 +513,32 @@ void CServerListManager::OnTimerPingCentralServer()
}
}
void CServerListManager::OnTimerCLRegisterServerResp()
{
QMutexLocker locker ( &Mutex );
if ( eSvrRegStatus == SRS_REQUESTED )
{
iSvrRegRetries++;
if ( iSvrRegRetries >= REGISTER_SERVER_RETRY_LIMIT )
{
eSvrRegStatus = SRS_TIME_OUT;
emit SvrRegStatusChanged();
}
else
{
locker.unlock();
{
OnTimerRegistering();
}
locker.relock();
// re-start timer for registration timeout
TimerCLRegisterServerResp.start();
}
}
}
void CServerListManager::SlaveServerRegisterServer ( const bool bIsRegister )
{
// we need the lock since the user might change the server properties at
@ -488,6 +562,9 @@ void CServerListManager::SlaveServerRegisterServer ( const bool bIsRegister )
if ( bIsRegister )
{
// register server
eSvrRegStatus = SRS_REQUESTED;
emit SvrRegStatusChanged();
pConnLessProtocol->CreateCLRegisterServerMes ( SlaveCurCentServerHostAddress,
SlaveCurLocalHostAddress,
ServerList[0] );
@ -495,7 +572,15 @@ void CServerListManager::SlaveServerRegisterServer ( const bool bIsRegister )
else
{
// unregister server
eSvrRegStatus = SRS_UNREGISTERED;
emit SvrRegStatusChanged();
pConnLessProtocol->CreateCLUnregisterServerMes ( SlaveCurCentServerHostAddress );
}
}
else
{
eSvrRegStatus = SRS_BAD_ADDRESS;
emit SvrRegStatusChanged();
}
}

View file

@ -171,6 +171,10 @@ public:
QLocale::Country GetServerCountry() { return ServerList[0].eCountry; }
ESvrRegStatus GetSvrRegStatus() { return eSvrRegStatus; }
void StoreRegistrationResult ( ESvrRegResult eStatus );
protected:
void SlaveServerRegisterServer ( const bool bIsRegister );
@ -178,6 +182,7 @@ protected:
QTimer TimerRegistering;
QTimer TimerPingServerInList;
QTimer TimerPingCentralServer;
QTimer TimerCLRegisterServerResp;
QMutex Mutex;
@ -195,10 +200,20 @@ protected:
CProtocol* pConnLessProtocol;
// server registration status
ESvrRegStatus eSvrRegStatus;
// count of registration retries
int iSvrRegRetries;
public slots:
void OnTimerPollList();
void OnTimerPingServerInList();
void OnTimerPingCentralServer();
void OnTimerCLRegisterServerResp();
void OnTimerRegistering() { SlaveServerRegisterServer ( true ); }
void OnTimerIsPermanent() { ServerList[0].bPermanentOnline = true; }
signals:
void SvrRegStatusChanged();
};

View file

@ -572,6 +572,27 @@ enum ECSAddType
};
// Slave server registration state ---------------------------------------------
enum ESvrRegStatus
{
SRS_UNREGISTERED = 0,
SRS_BAD_ADDRESS = 1,
SRS_REQUESTED = 2,
SRS_TIME_OUT = 3,
SRS_UNKNOWN_RESP = 4,
SRS_REGISTERED = 5,
SRS_CENTRAL_SVR_FULL = 6
};
// Central server registration outcome -----------------------------------------
enum ESvrRegResult
{
SRR_REGISTERED = 0,
SRR_CENTRAL_SVR_FULL = 1
};
// Skill level enum ------------------------------------------------------------
enum ESkillLevel
{