@ -14,22 +14,49 @@ GNU General Public License for more details.
@@ -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,65 +72,176 @@ qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data )
@@ -45,65 +72,176 @@ 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 )
switch ( NET_GetMasterHostByName ( list ) )
{
Con_Reportf ( " Can't resolve adr: %s \n " , list - > address ) ;
case NET_EAI_AGAIN :
list - > sent = false ;
wait = true ;
break ;
case NET_EAI_NONAME :
list - > sent = true ;
list - > adr . type = NA_UNUSED ;
continue ;
break ;
case NET_EAI_OK :
list - > sent = true ;
NET_SendPacket ( sock , len , data , list - > adr ) ;
break ;
}
}
if ( res = = 2 )
if ( ! wait )
{
// reset sent state
for ( list = ml . list ; list ; list = list - > next )
list - > sent = false ;
list - > adr . type = NA_UNUSED ;
wait = true ;
continue ;
}
list - > sent = true ;
return wait ;
}
NET_SendPacket ( sock , len , data , list - > adr ) ;
/*
= = = = = = = = = = = = = = = = = = = = = = = =
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 ) ;
}
}
if ( ! wait )
/*
= = = = = = = = = = = = = = = = = = = = = = = =
NET_AnnounceToMaster
= = = = = = = = = = = = = = = = = = = = = = = =
*/
void NET_MasterClear ( void )
{
list = ml . list ;
master_t * m ;
while ( list )
for ( m = ml . list ; m ; m = m - > next )
m - > last_heartbeat = MAX_HEARTBEAT ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
NET_MasterHeartbeat
= = = = = = = = = = = = = = = = = = = = = = = =
*/
void NET_MasterHeartbeat ( void )
{
list - > sent = false ;
list = list - > next ;
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 ;
}
}
}
return wait ;
/*
= = = = = = = = = = = = = = = = =
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_IsMasterAdr
NET_GetMasterFrom Adr
= = = = = = = = = = = = = = = = = = = = = = = =
*/
qboolean NET_IsMasterAdr ( netadr_t adr )
static master_t * NET_GetMasterFrom Adr( netadr_t adr )
{
master_t * master ;
for ( master = ml . list ; master ; master = master - > next )
{
if ( NET_CompareAdr ( adr , master - > adr ) )
return true ;
return mas te r;
}
return false ;
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
= = = = = = = = = = = = = = = = = = = = = = = =
*/
qboolean NET_IsMasterAdr ( netadr_t adr )
{
return NET_GetMasterFromAdr ( adr ) ! = NULL ;
}
/*
@ -277,6 +415,8 @@ void NET_InitMasters( void )
@@ -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 ( ) ;