mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-10 06:02:10 +08:00
engine: server: move master announce logic to masterlist, keep unique heartbeat challenge and heartbeat timer for each master
This commit is contained in:
@@ -876,6 +876,10 @@ void NET_InitMasters( void );
|
||||
void NET_SaveMasters( void );
|
||||
qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data );
|
||||
qboolean NET_IsMasterAdr( netadr_t adr );
|
||||
void NET_MasterHeartbeat( void );
|
||||
void NET_MasterClear( void );
|
||||
void NET_MasterShutdown( void );
|
||||
qboolean NET_GetMaster( netadr_t from, uint *challenge, double *last_heartbeat );
|
||||
|
||||
#ifdef REF_DLL
|
||||
#error "common.h in ref_dll"
|
||||
|
||||
+176
-36
@@ -14,22 +14,49 @@ GNU General Public License for more details.
|
||||
*/
|
||||
#include "common.h"
|
||||
#include "netchan.h"
|
||||
#include "server.h"
|
||||
|
||||
typedef struct master_s
|
||||
{
|
||||
struct master_s *next;
|
||||
qboolean sent;
|
||||
qboolean sent; // TODO: get rid of this internal state
|
||||
qboolean save;
|
||||
string address;
|
||||
netadr_t adr; // temporary, rewritten after each send
|
||||
|
||||
uint heartbeat_challenge;
|
||||
double last_heartbeat;
|
||||
} master_t;
|
||||
|
||||
struct masterlist_s
|
||||
static struct masterlist_s
|
||||
{
|
||||
master_t *list;
|
||||
qboolean modified;
|
||||
} ml;
|
||||
|
||||
static CVAR_DEFINE_AUTO( sv_verbose_heartbeats, "0", 0, "print every heartbeat to console" );
|
||||
|
||||
#define HEARTBEAT_SECONDS ((sv_nat.value > 0.0f) ? 60.0f : 300.0f) // 1 or 5 minutes
|
||||
|
||||
/*
|
||||
========================
|
||||
NET_GetMasterHostByName
|
||||
========================
|
||||
*/
|
||||
static net_gai_state_t NET_GetMasterHostByName( master_t *m )
|
||||
{
|
||||
net_gai_state_t res = NET_StringToAdrNB( m->address, &m->adr );
|
||||
|
||||
if( res == NET_EAI_OK )
|
||||
return res;
|
||||
|
||||
m->adr.type = NA_UNUSED;
|
||||
if( res == NET_EAI_NONAME )
|
||||
Con_Reportf( "Can't resolve adr: %s\n", m->address );
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
NET_SendToMasters
|
||||
@@ -45,48 +72,167 @@ qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data )
|
||||
|
||||
for( list = ml.list; list; list = list->next )
|
||||
{
|
||||
int res;
|
||||
|
||||
if( list->sent )
|
||||
continue;
|
||||
|
||||
res = NET_StringToAdrNB( list->address, &list->adr );
|
||||
|
||||
if( !res )
|
||||
{
|
||||
Con_Reportf( "Can't resolve adr: %s\n", list->address );
|
||||
list->sent = true;
|
||||
list->adr.type = NA_UNUSED;
|
||||
continue;
|
||||
}
|
||||
|
||||
if( res == 2 )
|
||||
switch( NET_GetMasterHostByName( list ))
|
||||
{
|
||||
case NET_EAI_AGAIN:
|
||||
list->sent = false;
|
||||
list->adr.type = NA_UNUSED;
|
||||
wait = true;
|
||||
continue;
|
||||
break;
|
||||
case NET_EAI_NONAME:
|
||||
list->sent = true;
|
||||
break;
|
||||
case NET_EAI_OK:
|
||||
list->sent = true;
|
||||
NET_SendPacket( sock, len, data, list->adr );
|
||||
break;
|
||||
}
|
||||
|
||||
list->sent = true;
|
||||
|
||||
NET_SendPacket( sock, len, data, list->adr );
|
||||
}
|
||||
|
||||
if( !wait )
|
||||
{
|
||||
list = ml.list;
|
||||
|
||||
while( list )
|
||||
{
|
||||
// reset sent state
|
||||
for( list = ml.list; list; list = list->next )
|
||||
list->sent = false;
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
return wait;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
NET_AnnounceToMaster
|
||||
|
||||
========================
|
||||
*/
|
||||
static void NET_AnnounceToMaster( master_t *m )
|
||||
{
|
||||
sizebuf_t msg;
|
||||
char buf[16];
|
||||
|
||||
m->heartbeat_challenge = COM_RandomLong( 0, INT_MAX );
|
||||
|
||||
MSG_Init( &msg, "Master Join", buf, sizeof( buf ));
|
||||
MSG_WriteBytes( &msg, "q\xFF", 2 );
|
||||
MSG_WriteDword( &msg, m->heartbeat_challenge );
|
||||
|
||||
NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &msg ), MSG_GetBuf( &msg ), m->adr );
|
||||
|
||||
if( sv_verbose_heartbeats.value )
|
||||
{
|
||||
Con_Printf( S_NOTE "sent heartbeat to %s (%s, 0x%x)\n",
|
||||
m->address, NET_AdrToString( m->adr ), m->heartbeat_challenge );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
NET_AnnounceToMaster
|
||||
|
||||
========================
|
||||
*/
|
||||
void NET_MasterClear( void )
|
||||
{
|
||||
master_t *m;
|
||||
|
||||
for( m = ml.list; m; m = m->next )
|
||||
m->last_heartbeat = MAX_HEARTBEAT;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
NET_MasterHeartbeat
|
||||
|
||||
========================
|
||||
*/
|
||||
void NET_MasterHeartbeat( void )
|
||||
{
|
||||
master_t *m;
|
||||
|
||||
if(( !public_server.value && !sv_nat.value ) || svs.maxclients == 1 )
|
||||
return; // only public servers send heartbeats
|
||||
|
||||
for( m = ml.list; m; m = m->next )
|
||||
{
|
||||
if( host.realtime - m->last_heartbeat < HEARTBEAT_SECONDS )
|
||||
continue;
|
||||
|
||||
switch( NET_GetMasterHostByName( m ))
|
||||
{
|
||||
case NET_EAI_AGAIN:
|
||||
m->last_heartbeat = MAX_HEARTBEAT; // retry on next frame
|
||||
if( sv_verbose_heartbeats.value )
|
||||
Con_Printf( S_NOTE "delay heartbeat to next frame until %s resolves\n", m->address );
|
||||
|
||||
break;
|
||||
case NET_EAI_NONAME:
|
||||
m->last_heartbeat = host.realtime; // try to resolve again on next heartbeat
|
||||
break;
|
||||
case NET_EAI_OK:
|
||||
m->last_heartbeat = host.realtime;
|
||||
NET_AnnounceToMaster( m );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
NET_MasterShutdown
|
||||
|
||||
Informs all masters that this server is going down
|
||||
(ignored by master servers in current implementation)
|
||||
=================
|
||||
*/
|
||||
void NET_MasterShutdown( void )
|
||||
{
|
||||
NET_Config( true, false ); // allow remote
|
||||
while( NET_SendToMasters( NS_SERVER, 2, "\x62\x0A" ));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
========================
|
||||
NET_GetMasterFromAdr
|
||||
|
||||
========================
|
||||
*/
|
||||
static master_t *NET_GetMasterFromAdr( netadr_t adr )
|
||||
{
|
||||
master_t *master;
|
||||
|
||||
for( master = ml.list; master; master = master->next )
|
||||
{
|
||||
if( NET_CompareAdr( adr, master->adr ))
|
||||
return master;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
========================
|
||||
NET_GetMaster
|
||||
========================
|
||||
*/
|
||||
qboolean NET_GetMaster( netadr_t from, uint *challenge, double *last_heartbeat )
|
||||
{
|
||||
master_t *m;
|
||||
|
||||
m = NET_GetMasterFromAdr( from );
|
||||
|
||||
if( m )
|
||||
{
|
||||
*challenge = m->heartbeat_challenge;
|
||||
*last_heartbeat = m->last_heartbeat;
|
||||
}
|
||||
|
||||
return m != NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
NET_IsMasterAdr
|
||||
@@ -95,15 +241,7 @@ NET_IsMasterAdr
|
||||
*/
|
||||
qboolean NET_IsMasterAdr( netadr_t adr )
|
||||
{
|
||||
master_t *master;
|
||||
|
||||
for( master = ml.list; master; master = master->next )
|
||||
{
|
||||
if( NET_CompareAdr( adr, master->adr ))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return NET_GetMasterFromAdr( adr ) != NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -277,6 +415,8 @@ void NET_InitMasters( void )
|
||||
Cmd_AddRestrictedCommand( "clearmasters", NET_ClearMasters_f, "clear masterserver list" );
|
||||
Cmd_AddCommand( "listmasters", NET_ListMasters_f, "list masterservers" );
|
||||
|
||||
Cvar_RegisterVariable( &sv_verbose_heartbeats );
|
||||
|
||||
// keep main master always there
|
||||
NET_AddMaster( MASTERSERVER_ADR, false );
|
||||
NET_LoadMasters( );
|
||||
|
||||
Reference in New Issue
Block a user