Skip to content

Commit 12716fd

Browse files
committed
engine(masterserver): Add sequence for requesting server info, implement StopRefresh and use it on timeout
1 parent a08b6ae commit 12716fd

File tree

6 files changed

+171
-67
lines changed

6 files changed

+171
-67
lines changed

engine/masterserver.cpp

Lines changed: 86 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818
#include "host.h"
1919
#include "eiface.h"
2020
#include "server.h"
21+
#include "utlmap.h"
2122

2223
extern ConVar sv_tags;
2324
extern ConVar sv_lan;
2425

2526
#define S2A_EXTRA_DATA_HAS_GAMETAG_DATA 0x01 // Next bytes are the game tag string
27+
#define RETRY_INFO_REQUEST_TIME 0.4 // seconds
28+
#define INFO_REQUEST_TIMEOUT 5.0 // seconds
2629

2730
//-----------------------------------------------------------------------------
2831
// Purpose: List of master servers and some state info about them
@@ -62,6 +65,7 @@ class CMaster : public IMaster, public IServersInfo
6265
void UseDefault ( void );
6366
void CheckHeartbeat (void);
6467
void RespondToHeartbeatChallenge( netadr_t &from, bf_read &msg );
68+
void PingServer( netadr_t &svadr );
6569

6670
void ProcessConnectionlessPacket( netpacket_t *packet );
6771

@@ -70,23 +74,35 @@ class CMaster : public IMaster, public IServersInfo
7074

7175
void RunFrame();
7276
void RequestServersInfo();
73-
void ReplyInfo( const netadr_t &adr );
77+
78+
void ReplyInfo( const netadr_t &adr, uint sequence );
7479
newgameserver_t &ProcessInfo( bf_read &buf );
7580

7681
// SeversInfo
7782
void RequestInternetServerList( const char *gamedir, IServerListResponse *response );
7883
void RequestLANServerList( const char *gamedir, IServerListResponse *response );
7984
void AddServerAddresses( netadr_t **adr, int count );
85+
void StopRefresh();
86+
8087
private:
8188
// List of known master servers
8289
adrlist_t *m_pMasterAddresses;
8390

8491
bool m_bInitialized;
92+
bool m_bWaitingForReplys;
93+
94+
int m_iServersResponded;
95+
96+
double m_flStartRequestTime;
97+
double m_flRetryRequestTime;
98+
99+
uint m_iInfoSequence;
85100

86101
// If nomaster is true, the server will not send heartbeats to the master server
87102
bool m_bNoMasters;
88103

89-
CUtlLinkedList<netadr_t> m_serverAddresses;
104+
CUtlMap<netadr_t, bool> m_serverAddresses;
105+
CUtlMap<uint, double> m_serversRequestTime;
90106

91107
IServerListResponse *m_serverListResponse;
92108
};
@@ -108,8 +124,13 @@ CMaster::CMaster( void )
108124
m_pMasterAddresses = NULL;
109125
m_bNoMasters = false;
110126
m_bInitialized = false;
127+
m_iServersResponded = 0;
111128

112129
m_serverListResponse = NULL;
130+
SetDefLessFunc( m_serverAddresses );
131+
SetDefLessFunc( m_serversRequestTime );
132+
m_bWaitingForReplys = false;
133+
m_iInfoSequence = 0;
113134

114135
Init();
115136
}
@@ -121,9 +142,34 @@ CMaster::~CMaster( void )
121142
void CMaster::RunFrame()
122143
{
123144
CheckHeartbeat();
145+
146+
if( !m_bWaitingForReplys )
147+
return;
148+
149+
if( m_serverListResponse &&
150+
m_flStartRequestTime < Plat_FloatTime()-INFO_REQUEST_TIMEOUT )
151+
{
152+
m_serverListResponse->RefreshComplete( NServerResponse::nServerFailedToRespond );
153+
m_bWaitingForReplys = false;
154+
}
155+
156+
if( m_flRetryRequestTime < Plat_FloatTime() - RETRY_INFO_REQUEST_TIME )
157+
{
158+
m_flRetryRequestTime = Plat_FloatTime();
159+
160+
if( m_iServersResponded < m_serverAddresses.Count() )
161+
RequestServersInfo();
162+
}
124163
}
125164

126-
void CMaster::ReplyInfo( const netadr_t &adr )
165+
void CMaster::StopRefresh()
166+
{
167+
m_bWaitingForReplys = false;
168+
m_serverAddresses.RemoveAll();
169+
m_serversRequestTime.RemoveAll();
170+
}
171+
172+
void CMaster::ReplyInfo( const netadr_t &adr, uint sequence )
127173
{
128174
static char gamedir[MAX_OSPATH];
129175
Q_FileBase( com_gamedir, gamedir, sizeof( gamedir ) );
@@ -134,6 +180,7 @@ void CMaster::ReplyInfo( const netadr_t &adr )
134180
buf.PutUnsignedInt( LittleDWord( CONNECTIONLESS_HEADER ) );
135181
buf.PutUnsignedChar( S2C_INFOREPLY );
136182

183+
buf.PutUnsignedInt(sequence);
137184
buf.PutUnsignedChar( PROTOCOL_VERSION ); // Hardcoded protocol version number
138185
buf.PutString( sv.GetName() );
139186
buf.PutString( sv.GetMapName() );
@@ -217,8 +264,7 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
217264
}
218265
case M2C_QUERY:
219266
{
220-
if( m_serverAddresses.Count() > 0 )
221-
m_serverAddresses.RemoveAll();
267+
m_serverAddresses.RemoveAll();
222268

223269
ip = msg.ReadLong();
224270
port = msg.ReadShort();
@@ -227,33 +273,48 @@ void CMaster::ProcessConnectionlessPacket( netpacket_t *packet )
227273
{
228274
netadr_t adr(ip, port);
229275

230-
m_serverAddresses.AddToHead(adr);
276+
m_serverAddresses.Insert(adr, false);
231277

232278
ip = msg.ReadLong();
233279
port = msg.ReadShort();
234280
}
235281

282+
m_iServersResponded = 0;
236283
RequestServersInfo();
284+
m_flRetryRequestTime = m_flStartRequestTime = Plat_FloatTime();
237285
break;
238286
}
239287
case C2S_INFOREQUEST:
240288
{
241-
ReplyInfo(packet->from);
289+
ReplyInfo(packet->from, msg.ReadLong());
242290
break;
243291
}
244292
case S2C_INFOREPLY:
245293
{
294+
uint sequence = msg.ReadLong();
246295
newgameserver_t &s = ProcessInfo( msg );
247-
Msg("hostname = %s\nplayers: %d/%d\nbots: %d\n", s.m_szServerName, s.m_nPlayers, s.m_nMaxPlayers, s.m_nBotPlayers);
248296

297+
unsigned short index = m_serverAddresses.Find(packet->from);
298+
unsigned short rindex = m_serversRequestTime.Find(sequence);
299+
300+
if( index == m_serverAddresses.InvalidIndex() ||
301+
rindex == m_serversRequestTime.InvalidIndex() )
302+
break;
303+
304+
double requestTime = m_serversRequestTime[rindex];
305+
306+
m_serverAddresses[index] = true;
307+
s.m_nPing = (packet->received-requestTime)*1000.0;
249308
s.m_NetAdr = packet->from;
250309
m_serverListResponse->ServerResponded( s );
251-
break;
252-
}
253-
case A2A_PING:
254-
{
255-
const char p = A2A_ACK;
256-
NET_SendPacket( NULL, NS_SERVER, packet->from, (unsigned char*)&p, 1);
310+
311+
m_iServersResponded++;
312+
313+
if( m_iServersResponded >= m_serverAddresses.Count() )
314+
{
315+
StopRefresh();
316+
m_serverListResponse->RefreshComplete( NServerResponse::nServerResponded );
317+
}
257318
break;
258319
}
259320
}
@@ -265,17 +326,24 @@ void CMaster::RequestServersInfo()
265326

266327
bf_write msg( string, sizeof(string) );
267328

268-
FOR_EACH_LL( m_serverAddresses, i )
329+
FOR_EACH_MAP_FAST( m_serverAddresses, i )
269330
{
270-
const netadr_t adr = m_serverAddresses[i];
331+
bool bResponded = m_serverAddresses.Element(i);
332+
if( bResponded )
333+
continue;
271334

272-
Msg("Request server info %s\n", adr.ToString());
335+
const netadr_t adr = m_serverAddresses.Key(i);
273336

274337
msg.WriteLong( CONNECTIONLESS_HEADER );
275338
msg.WriteByte( C2S_INFOREQUEST );
339+
msg.WriteLong( m_iInfoSequence );
340+
m_serversRequestTime.Insert(m_iInfoSequence, net_time);
276341

342+
m_iInfoSequence++;
277343
NET_SendPacket( NULL, NS_CLIENT, adr, msg.GetData(), msg.GetNumBytesWritten() );
278344
}
345+
346+
m_bWaitingForReplys = true;
279347
}
280348

281349
//-----------------------------------------------------------------------------
@@ -410,7 +478,7 @@ void CMaster::AddServer( netadr_t *adr )
410478

411479
n = ( adrlist_t * ) malloc ( sizeof( adrlist_t ) );
412480
if ( !n )
413-
Sys_Error( "Error allocating %i bytes for master address.", sizeof( adrlist_t ) );
481+
Sys_Error( "Error allocating %zd bytes for master address.", sizeof( adrlist_t ) );
414482

415483
memset( n, 0, sizeof( adrlist_t ) );
416484

public/engine/iserversinfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ class IServersInfo
8989
public:
9090
virtual void RequestInternetServerList( const char *gamedir, IServerListResponse *response ) = 0;
9191
virtual void RequestLANServerList( const char *gamedir, IServerListResponse *response ) = 0;
92+
virtual void StopRefresh() = 0;
9293

9394
//virtual HServerQuery PingServer( uint32 unIP, uint16 usPort, ISteamMatchmakingPingResponse *pRequestServersResponse ) = 0;
9495
//virtual HServerQuery PlayerDetails( uint32 unIP, uint16 usPort, ISteamMatchmakingPlayersResponse *pRequestServersResponse ) = 0;

public/tier0/threadtools.h

Lines changed: 5 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,6 @@
5252
#pragma once
5353
#pragma warning(push)
5454
#pragma warning(disable:4251)
55-
56-
extern "C"
57-
{
58-
void __declspec(dllimport) __stdcall Sleep( unsigned long );
59-
}
60-
6155
#endif
6256

6357
#ifdef COMPILER_MSVC64
@@ -200,6 +194,8 @@ PLATFORM_INTERFACE bool ReleaseThreadHandle( ThreadHandle_t );
200194

201195
//-----------------------------------------------------------------------------
202196

197+
PLATFORM_INTERFACE void ThreadSleep(unsigned duration = 0);
198+
PLATFORM_INTERFACE void ThreadNanoSleep(unsigned ns);
203199
PLATFORM_INTERFACE ThreadId_t ThreadGetCurrentId();
204200
PLATFORM_INTERFACE ThreadHandle_t ThreadGetCurrentHandle();
205201
PLATFORM_INTERFACE int ThreadGetPriority( ThreadHandle_t hThread = NULL );
@@ -233,10 +229,10 @@ inline void ThreadPause()
233229
{
234230
#if defined( COMPILER_PS3 )
235231
__db16cyc();
236-
#elif defined( COMPILER_GCC ) && (defined( __i386__ ) || defined( __x86_64__ ))
237-
__asm __volatile( "pause" );
238-
#elif defined( POSIX )
232+
#elif defined(__arm__) || defined(__aarch64__)
239233
sched_yield();
234+
#elif defined( COMPILER_GCC )
235+
__asm __volatile( "pause" );
240236
#elif defined ( COMPILER_MSVC64 )
241237
_mm_pause();
242238
#elif defined( COMPILER_MSVC32 )
@@ -251,36 +247,6 @@ inline void ThreadPause()
251247
#endif
252248
}
253249

254-
inline void ThreadSleep(unsigned nMilliseconds = 0)
255-
{
256-
if( nMilliseconds == 0 )
257-
{
258-
ThreadPause();
259-
return;
260-
}
261-
262-
#ifdef _WIN32
263-
264-
#ifdef _WIN32_PC
265-
static bool bInitialized = false;
266-
if ( !bInitialized )
267-
{
268-
bInitialized = true;
269-
// Set the timer resolution to 1 ms (default is 10.0, 15.6, 2.5, 1.0 or
270-
// some other value depending on hardware and software) so that we can
271-
// use Sleep( 1 ) to avoid wasting CPU time without missing our frame
272-
// rate.
273-
timeBeginPeriod( 1 );
274-
}
275-
#endif
276-
Sleep( nMilliseconds );
277-
#elif PS3
278-
sys_timer_usleep( nMilliseconds * 1000 );
279-
#elif defined(POSIX)
280-
usleep( nMilliseconds * 1000 );
281-
#endif
282-
}
283-
284250
PLATFORM_INTERFACE bool ThreadJoin( ThreadHandle_t, unsigned timeout = TT_INFINITE );
285251

286252
PLATFORM_INTERFACE void ThreadSetDebugName( ThreadHandle_t hThread, const char *pszName );

public/tier1/memhelpers.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,21 @@ namespace memutils
1111
template<typename T>
1212
inline void copy( T *dest, const T *src, size_t n )
1313
{
14-
for(; n; n--)
15-
*(dest++) = *(src++);
14+
do
15+
{
16+
--n;
17+
*(dest+n) = *(src+n);
18+
} while( n );
1619
}
1720

1821
template<typename T>
19-
inline void set( T *dest, const T& value, size_t n )
22+
inline void set( T *dest, T value, size_t n )
2023
{
21-
for(; n; n--)
22-
*(dest++) = value;
24+
do
25+
{
26+
--n;
27+
*(dest+n) = value;
28+
} while( n );
2329
}
2430
}
2531

tier0/threadtools.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,59 @@ bool ReleaseThreadHandle( ThreadHandle_t hThread )
485485
//
486486
//-----------------------------------------------------------------------------
487487

488+
void ThreadSleep(unsigned nMilliseconds)
489+
{
490+
#ifdef _WIN32
491+
492+
#ifdef _WIN32_PC
493+
static bool bInitialized = false;
494+
if ( !bInitialized )
495+
{
496+
bInitialized = true;
497+
// Set the timer resolution to 1 ms (default is 10.0, 15.6, 2.5, 1.0 or
498+
// some other value depending on hardware and software) so that we can
499+
// use Sleep( 1 ) to avoid wasting CPU time without missing our frame
500+
// rate.
501+
timeBeginPeriod( 1 );
502+
}
503+
#endif
504+
505+
Sleep( nMilliseconds );
506+
#elif PS3
507+
if( nMilliseconds == 0 )
508+
{
509+
// sys_ppu_thread_yield doesn't seem to function properly, so sleep instead.
510+
// sys_timer_usleep( 60 );
511+
sys_ppu_thread_yield();
512+
}
513+
else
514+
{
515+
sys_timer_usleep( nMilliseconds * 1000 );
516+
}
517+
#elif defined(POSIX)
518+
usleep( nMilliseconds * 1000 );
519+
#endif
520+
}
521+
522+
//-----------------------------------------------------------------------------
523+
void ThreadNanoSleep(unsigned ns)
524+
{
525+
#ifdef _WIN32
526+
// ceil
527+
Sleep( ( ns + 999 ) / 1000 );
528+
#elif PS3
529+
sys_timer_usleep( ns );
530+
#elif defined(POSIX)
531+
struct timespec tm;
532+
tm.tv_sec = 0;
533+
tm.tv_nsec = ns;
534+
nanosleep( &tm, NULL );
535+
#endif
536+
}
537+
538+
539+
//-----------------------------------------------------------------------------
540+
488541
#ifndef ThreadGetCurrentId
489542
ThreadId_t ThreadGetCurrentId()
490543
{

0 commit comments

Comments
 (0)