Add masterlist from engine. Use non-blocking network name resolution

This commit is contained in:
Alibek Omarov 2018-06-01 20:44:16 +03:00
parent 5a449a56ea
commit ae5257c654
13 changed files with 322 additions and 26 deletions

View File

@ -146,6 +146,7 @@ engine/common/library.h
engine/common/mathlib.c engine/common/mathlib.c
engine/common/mathlib.h engine/common/mathlib.h
engine/common/matrixlib.c engine/common/matrixlib.c
engine/common/masterlist.c
engine/common/mod_bmodel.c engine/common/mod_bmodel.c
engine/common/mod_local.h engine/common/mod_local.h
engine/common/mod_studio.c engine/common/mod_studio.c

View File

@ -1020,6 +1020,10 @@ Resend a connect message if the last one has timed out
void CL_CheckForResend( void ) void CL_CheckForResend( void )
{ {
netadr_t adr; netadr_t adr;
int res;
if( cls.internetservers_wait )
CL_InternetServers_f();
// if the local server is running and we aren't then connect // if the local server is running and we aren't then connect
if( cls.state == ca_disconnected && SV_Active( )) if( cls.state == ca_disconnected && SV_Active( ))
@ -1044,13 +1048,21 @@ void CL_CheckForResend( void )
if(( host.realtime - cls.connect_time ) < cl_resend.value ) if(( host.realtime - cls.connect_time ) < cl_resend.value )
return; return;
if( !NET_StringToAdr( cls.servername, &adr )) res = NET_StringToAdrNB( cls.servername, &adr );
if( !res )
{ {
MsgDev( D_ERROR, "CL_CheckForResend: bad server address\n" ); MsgDev( D_ERROR, "CL_CheckForResend: bad server address\n" );
CL_Disconnect(); CL_Disconnect();
return; return;
} }
if( res == 2 )
{
cls.connect_time = MAX_HEARTBEAT;
return;
}
// only retry so many times before failure. // only retry so many times before failure.
if( cls.connect_retry >= CL_CONNECTION_RETRIES ) if( cls.connect_retry >= CL_CONNECTION_RETRIES )
{ {
@ -1424,6 +1436,8 @@ void CL_LocalServers_f( void )
Netchan_OutOfBandPrint( NS_CLIENT, adr, "info %i", PROTOCOL_VERSION ); Netchan_OutOfBandPrint( NS_CLIENT, adr, "info %i", PROTOCOL_VERSION );
} }
#define MS_SCAN_REQUEST "1\xFF" "0.0.0.0:0\0"
/* /*
================= =================
CL_InternetServers_f CL_InternetServers_f
@ -1431,23 +1445,28 @@ CL_InternetServers_f
*/ */
void CL_InternetServers_f( void ) void CL_InternetServers_f( void )
{ {
netadr_t adr; char fullquery[512] = MS_SCAN_REQUEST;
char fullquery[512] = "1\xFF" "0.0.0.0:0\0" "\\gamedir\\"; char *info = fullquery + sizeof( MS_SCAN_REQUEST ) - 1;
const size_t remaining = sizeof( fullquery ) - sizeof( MS_SCAN_REQUEST );
// Info_SetValueForKey( info, "nat", cl_nat->string, remaining );
Info_SetValueForKey( info, "gamedir", GI->gamefolder, remaining );
// let master know about client version
Info_SetValueForKey( info, "clver", XASH_VERSION, remaining );
Con_Printf( "Scanning for servers on the internet area...\n" );
NET_Config( true ); // allow remote NET_Config( true ); // allow remote
if( !NET_StringToAdr( MASTERSERVER_ADR, &adr ) ) cls.internetservers_wait = NET_SendToMasters( NS_CLIENT, sizeof( MS_SCAN_REQUEST ) + Q_strlen( info ), fullquery );
MsgDev( D_ERROR, "Can't resolve adr: %s\n", MASTERSERVER_ADR ); cls.internetservers_pending = true;
Q_strcpy( &fullquery[22], GI->gamefolder ); if( !cls.internetservers_wait )
{
NET_SendPacket( NS_CLIENT, Q_strlen( GI->gamefolder ) + 23, fullquery, adr ); // now we clearing the vgui request
if( clgame.master_request != NULL )
// now we clearing the vgui request memset( clgame.master_request, 0, sizeof( net_request_t ));
if( clgame.master_request != NULL ) clgame.request_type = NET_REQUEST_GAMEUI;
memset( clgame.master_request, 0, sizeof( net_request_t )); }
clgame.request_type = NET_REQUEST_GAMEUI;
} }
/* /*
@ -1907,6 +1926,12 @@ void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
Netchan_OutOfBandPrint( NS_CLIENT, servadr, "info %i", PROTOCOL_VERSION ); Netchan_OutOfBandPrint( NS_CLIENT, servadr, "info %i", PROTOCOL_VERSION );
} }
} }
if( cls.internetservers_pending )
{
Cbuf_AddText( "menu_resetping\n" ); // TODO: New Menu API
cls.internetservers_pending = false;
}
} }
else if( clgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len )) else if( clgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
{ {

View File

@ -54,7 +54,7 @@ static void Vibrate_f()
{ {
if( Cmd_Argc() != 2 ) if( Cmd_Argc() != 2 )
{ {
Msg( "Usage: vibrate <time>\n" ); Msg( S_USAGE "vibrate <time>\n" );
return; return;
} }

View File

@ -648,6 +648,8 @@ typedef struct
file_t *demofile; file_t *demofile;
file_t *demoheader; // contain demo startup info in case we record a demo on this level file_t *demoheader; // contain demo startup info in case we record a demo on this level
qboolean internetservers_wait; // internetservers is waiting for dns request
qboolean internetservers_pending; // internetservers is waiting for dns request
} client_static_t; } client_static_t;
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -183,7 +183,7 @@ void Evdev_OpenDevice ( const char *path )
void Evdev_OpenDevice_f( void ) void Evdev_OpenDevice_f( void )
{ {
if( Cmd_Argc() < 2 ) if( Cmd_Argc() < 2 )
Msg( "Usage: evdev_opendevice <path>\n" ); Msg( S_USAGE "evdev_opendevice <path>\n" );
Evdev_OpenDevice( Cmd_Argv( 1 ) ); Evdev_OpenDevice( Cmd_Argv( 1 ) );
} }

View File

@ -250,7 +250,7 @@ void IN_TouchExportConfig_f( void )
if( Cmd_Argc() != 2 ) if( Cmd_Argc() != 2 )
{ {
Msg( "Usage: touch_exportconfig <name>\n" ); Msg( S_USAGE "touch_exportconfig <name>\n" );
return; return;
} }
@ -340,7 +340,7 @@ void IN_TouchGenetateCode_f( void )
if( Cmd_Argc() != 1 ) if( Cmd_Argc() != 1 )
{ {
Msg( "Usage: touch_generate_code\n" ); Msg( S_USAGE "touch_generate_code\n" );
return; return;
} }
@ -584,7 +584,7 @@ void IN_TouchSetColor_f( void )
IN_TouchSetColor( &touch.list_user, Cmd_Argv(1), color ); IN_TouchSetColor( &touch.list_user, Cmd_Argv(1), color );
return; return;
} }
Msg( "Usage: touch_setcolor <pattern> <r> <g> <b> <a>\n" ); Msg( S_USAGE "touch_setcolor <pattern> <r> <g> <b> <a>\n" );
} }
void IN_TouchSetTexture_f( void ) void IN_TouchSetTexture_f( void )
@ -594,7 +594,7 @@ void IN_TouchSetTexture_f( void )
IN_TouchSetTexture( &touch.list_user, Cmd_Argv( 1 ), Cmd_Argv( 2 ) ); IN_TouchSetTexture( &touch.list_user, Cmd_Argv( 1 ), Cmd_Argv( 2 ) );
return; return;
} }
Msg( "Usage: touch_settexture <name> <file>\n" ); Msg( S_USAGE "touch_settexture <name> <file>\n" );
} }
void IN_TouchSetFlags_f( void ) void IN_TouchSetFlags_f( void )
@ -606,7 +606,7 @@ void IN_TouchSetFlags_f( void )
button->flags = Q_atoi( Cmd_Argv( 2 ) ); button->flags = Q_atoi( Cmd_Argv( 2 ) );
return; return;
} }
Msg( "Usage: touch_setflags <name> <file>\n" ); Msg( S_USAGE "touch_setflags <name> <file>\n" );
} }
void IN_TouchSetCommand_f( void ) void IN_TouchSetCommand_f( void )
@ -616,7 +616,7 @@ void IN_TouchSetCommand_f( void )
IN_TouchSetCommand( &touch.list_user, Cmd_Argv( 1 ), Cmd_Argv( 2 ) ); IN_TouchSetCommand( &touch.list_user, Cmd_Argv( 1 ), Cmd_Argv( 2 ) );
return; return;
} }
Msg( "Usage: touch_command <name> <command>\n" ); Msg( S_USAGE "touch_command <name> <command>\n" );
} }
void IN_TouchReloadConfig_f( void ) void IN_TouchReloadConfig_f( void )
{ {
@ -779,7 +779,7 @@ void IN_TouchAddButton_f( void )
IN_TouchAddButton( &touch.list_user, Cmd_Argv(1), Cmd_Argv(2), Cmd_Argv(3), 0.4, 0.4, 0.6, 0.6, color ); IN_TouchAddButton( &touch.list_user, Cmd_Argv(1), Cmd_Argv(2), Cmd_Argv(3), 0.4, 0.4, 0.6, 0.6, color );
return; return;
} }
Msg( "Usage: touch_addbutton <name> <texture> <command> [<x1> <y1> <x2> <y2> [ r g b a ] ]\n" ); Msg( S_USAGE "touch_addbutton <name> <texture> <command> [<x1> <y1> <x2> <y2> [ r g b a ] ]\n" );
} }
void IN_TouchEnableEdit_f( void ) void IN_TouchEnableEdit_f( void )
@ -806,7 +806,7 @@ void IN_TouchDeleteProfile_f( void )
{ {
if( Cmd_Argc() != 2 ) if( Cmd_Argc() != 2 )
{ {
Msg( "Usage: touch_deleteprofile <name>\n" ); Msg( S_USAGE "touch_deleteprofile <name>\n" );
return; return;
} }

View File

@ -404,7 +404,7 @@ static void VID_Mode_f( void )
break; break;
} }
default: default:
Msg( "Usage: vid_mode <modenum>|<width height>\n" ); Msg( S_USAGE "vid_mode <modenum>|<width height>\n" );
return; return;
} }

View File

@ -1096,6 +1096,13 @@ typedef struct sentenceEntry_ sentenceEntry_s;
sequenceEntry_s *Sequence_Get( const char *fileName, const char *entryName ); sequenceEntry_s *Sequence_Get( const char *fileName, const char *entryName );
sentenceEntry_s *Sequence_PickSentence( const char *groupName, int pickMethod, int *picked ); sentenceEntry_s *Sequence_PickSentence( const char *groupName, int pickMethod, int *picked );
//
// masterlist.c
//
void NET_InitMasters( void );
void NET_SaveMasters( void );
qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data );
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -951,6 +951,8 @@ void Host_WriteConfig( void )
FS_Close( f ); FS_Close( f );
} }
else MsgDev( D_ERROR, "Couldn't write config.cfg.\n" ); else MsgDev( D_ERROR, "Couldn't write config.cfg.\n" );
NET_SaveMasters();
} }
#endif #endif

View File

@ -906,6 +906,7 @@ int EXPORT Host_Main( int argc, char **argv, const char *progname, int bChangeGa
Mod_Init(); Mod_Init();
NET_Init(); NET_Init();
NET_InitMasters();
Netchan_Init(); Netchan_Init();
// allow to change game from the console // allow to change game from the console

256
engine/common/masterlist.c Normal file
View File

@ -0,0 +1,256 @@
/*
masterlist.c - multi-master list
Copyright (C) 2018 mittorn
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 Foundation, either version 3 of the License, or
(at your option) any later version.
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 FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "common.h"
#include "netchan.h"
typedef struct master_s
{
struct master_s *next;
qboolean sent;
qboolean save;
string address;
} master_t;
struct masterlist_s
{
master_t *list;
qboolean modified;
} ml;
/*
========================
NET_SendToMasters
Send request to all masterservers list
return true if would block
========================
*/
qboolean NET_SendToMasters( netsrc_t sock, size_t len, const void *data )
{
master_t *list;
qboolean wait = false;
for( list = ml.list; list; list = list->next )
{
netadr_t adr;
int res;
if( list->sent )
continue;
res = NET_StringToAdrNB( list->address, &adr );
if( !res )
{
MsgDev( D_INFO, "Can't resolve adr: %s\n", list->address );
list->sent = true;
continue;
}
if( res == 2 )
{
list->sent = false;
wait = true;
continue;
}
list->sent = true;
NET_SendPacket( sock, len, data, adr );
}
if( !wait )
{
list = ml.list;
while( list )
{
list->sent = false;
list = list->next;
}
}
return wait;
}
/*
========================
NET_AddMaster
Add master to the list
========================
*/
static void NET_AddMaster( char *addr, qboolean save )
{
master_t *master, *last;
for( last = ml.list; last && last->next; last = last->next )
{
if( !Q_strcmp( last->address, addr ) ) // already exists
return;
}
master = Mem_Alloc( host.mempool, sizeof( master_t ) );
Q_strncpy( master->address, addr, MAX_STRING );
master->sent = false;
master->save = save;
master->next = NULL;
// link in
if( last )
last->next = master;
else
ml.list = master;
}
static void NET_AddMaster_f( void )
{
if( Cmd_Argc() != 2 )
{
Msg( S_USAGE "addmaster <address>\n");
return;
}
NET_AddMaster( Cmd_Argv( 1 ), true ); // save them into config
ml.modified = true; // save config
}
/*
========================
NET_ClearMasters
Clear master list
========================
*/
static void NET_ClearMasters_f( void )
{
while( ml.list )
{
master_t *prev = ml.list;
ml.list = ml.list->next;
Mem_Free( prev );
}
}
/*
========================
NET_ListMasters_f
Display current master linked list
========================
*/
static void NET_ListMasters_f( void )
{
master_t *list;
int i;
Msg( "Master servers\n=============\n" );
for( i = 1, list = ml.list; list; i++, list = list->next )
{
Msg( "%d\t%s\n", i, list->address );
}
}
/*
========================
NET_LoadMasters
Load master server list from xashcomm.lst
========================
*/
static void NET_LoadMasters( void )
{
byte *afile, *pfile;
char token[MAX_TOKEN];
pfile = afile = FS_LoadFile( "xashcomm.lst", NULL, true );
if( !afile ) // file doesn't exist yet
{
MsgDev( D_INFO, "Cannot load xashcomm.lst\n" );
return;
}
// format: master <addr>\n
while( ( pfile = COM_ParseFile( pfile, token ) ) )
{
if( !Q_strcmp( token, "master" ) ) // load addr
{
pfile = COM_ParseFile( pfile, token );
NET_AddMaster( token, true );
}
}
Mem_Free( afile );
ml.modified = false;
}
/*
========================
NET_SaveMasters
Save master server list to xashcomm.lst, except for default
========================
*/
void NET_SaveMasters( void )
{
file_t *f;
master_t *m;
if( !ml.modified )
{
MsgDev( D_NOTE, "Master server list not changed\n" );
return;
}
f = FS_Open( "xashcomm.lst", "w", true );
if( !f )
{
MsgDev( D_ERROR, "Couldn't write xashcomm.lst\n" );
return;
}
for( m = ml.list; m; m = m->next )
{
if( m->save )
FS_Printf( f, "master %s\n", m->address );
}
FS_Close( f );
}
/*
========================
NET_InitMasters
Initialize master server list
========================
*/
void NET_InitMasters( void )
{
Cmd_AddRestrictedCommand( "addmaster", NET_AddMaster_f, "add address to masterserver list" );
Cmd_AddRestrictedCommand( "clearmasters", NET_ClearMasters_f, "clear masterserver list" );
Cmd_AddCommand( "listmasters", NET_ListMasters_f, "list masterservers" );
// keep main master always there
NET_AddMaster( MASTERSERVER_ADR, false );
NET_AddMaster( MASTERSERVER_ADR2, false );
NET_LoadMasters( );
}

View File

@ -54,6 +54,7 @@ char *NET_BaseAdrToString( const netadr_t a );
qboolean NET_IsReservedAdr( netadr_t a ); qboolean NET_IsReservedAdr( netadr_t a );
qboolean NET_CompareClassBAdr( netadr_t a, netadr_t b ); qboolean NET_CompareClassBAdr( netadr_t a, netadr_t b );
qboolean NET_StringToAdr( const char *string, netadr_t *adr ); qboolean NET_StringToAdr( const char *string, netadr_t *adr );
int NET_StringToAdrNB( const char *string, netadr_t *adr );
qboolean NET_CompareAdr( const netadr_t a, const netadr_t b ); qboolean NET_CompareAdr( const netadr_t a, const netadr_t b );
qboolean NET_CompareBaseAdr( const netadr_t a, const netadr_t b ); qboolean NET_CompareBaseAdr( const netadr_t a, const netadr_t b );
qboolean NET_GetPacket( netsrc_t sock, netadr_t *from, byte *data, size_t *length ); qboolean NET_GetPacket( netsrc_t sock, netadr_t *from, byte *data, size_t *length );
@ -62,4 +63,4 @@ qboolean NET_BufferToBufferDecompress( char *dest, uint *destLen, char *source,
void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to ); void NET_SendPacket( netsrc_t sock, size_t length, const void *data, netadr_t to );
void NET_ClearLagData( qboolean bClient, qboolean bServer ); void NET_ClearLagData( qboolean bClient, qboolean bServer );
#endif//NET_WS_H #endif//NET_WS_H

View File

@ -70,6 +70,7 @@ GNU General Public License for more details.
#define NET_MAX_MESSAGE PAD_NUMBER(( NET_MAX_PAYLOAD + HEADER_BYTES ), 16 ) #define NET_MAX_MESSAGE PAD_NUMBER(( NET_MAX_PAYLOAD + HEADER_BYTES ), 16 )
#define MASTERSERVER_ADR "ms.xash.su:27010" #define MASTERSERVER_ADR "ms.xash.su:27010"
#define MASTERSERVER_ADR2 "ms2.xash.su:27010"
#define PORT_MASTER 27010 #define PORT_MASTER 27010
#define PORT_CLIENT 27005 #define PORT_CLIENT 27005
#define PORT_SERVER 27015 #define PORT_SERVER 27015