2017-09-20 11:27:13 +00:00
/*
Contains the control routines that handle both incoming and outgoing stuff
*/
# include "qtv.h"
# include <signal.h>
# include "bsd_string.h"
# ifndef _WIN32
# include <sys/stat.h>
2009-07-07 23:40:06 +00:00
# include <dirent.h>
# else
2017-09-20 11:27:13 +00:00
# include <direct.h>
# endif
typedef struct {
char name [ 56 ] ;
int offset ;
int length ;
} pakfile ;
// PACK, offset, lengthofpakfiles
FILE * FindInPaks ( char * gamedir , char * filename , int * size )
{
FILE * f ;
char fname [ 1024 ] ;
int i , j ;
int numfiles ;
unsigned int header [ 3 ] ;
pakfile pf ;
for ( i = 0 ; ; i + + )
{
sprintf ( fname , " %s/pak%i.pak " , gamedir , i ) ;
f = fopen ( fname , " rb " ) ;
if ( ! f )
return NULL ; //ran out of possible pak files.
fread ( header , 1 , sizeof ( header ) , f ) ;
if ( header [ 0 ] ! = * ( unsigned int * ) " PACK " )
{ //err... hmm.
fclose ( f ) ;
continue ;
}
numfiles = LittleLong ( header [ 2 ] ) / sizeof ( pakfile ) ;
fseek ( f , LittleLong ( header [ 1 ] ) , SEEK_SET ) ;
for ( j = 0 ; j < numfiles ; j + + )
{
fread ( & pf , 1 , sizeof ( pf ) , f ) ;
if ( ! strcmp ( pf . name , filename ) )
{
fseek ( f , LittleLong ( pf . offset ) , 0 ) ;
if ( size )
* size = LittleLong ( pf . length ) ;
return f ;
}
}
fclose ( f ) ;
//not found
}
return NULL ;
}
unsigned char * FS_ReadFile2 ( char * gamedir , char * filename , unsigned int * sizep )
{
int size ;
unsigned char * data ;
FILE * f ;
char fname [ 1024 ] ;
if ( ! * filename )
return NULL ;
//try and read it straight out of the file system
sprintf ( fname , " %s/%s " , gamedir , filename ) ;
f = fopen ( fname , " rb " ) ;
if ( ! f )
f = fopen ( filename , " rb " ) ; //see if we're being run from inside the gamedir
if ( ! f )
{
f = FindInPaks ( gamedir , filename , & size ) ;
if ( ! f )
f = FindInPaks ( " id1 " , filename , & size ) ;
if ( ! f )
{
return NULL ;
}
}
else
{
fseek ( f , 0 , SEEK_END ) ;
size = ftell ( f ) ;
fseek ( f , 0 , SEEK_SET ) ;
}
data = malloc ( size ) ;
if ( data )
fread ( data , 1 , size , f ) ;
fclose ( f ) ;
if ( sizep )
* sizep = size ;
return data ;
}
unsigned char * FS_ReadFile ( char * gamedir , char * filename , unsigned int * size )
{
unsigned char * data ;
if ( ! gamedir | | ! * gamedir | | ! strcmp ( gamedir , " qw " ) )
data = NULL ;
else
data = FS_ReadFile2 ( gamedir , filename , size ) ;
if ( ! data )
{
data = FS_ReadFile2 ( " qw " , filename , size ) ;
if ( ! data )
{
data = FS_ReadFile2 ( " id1 " , filename , size ) ;
if ( ! data )
{
return NULL ;
}
}
}
return data ;
}
# ifndef _WIN32
# define _cdecl
# endif
int _cdecl SortFilesByDate ( const void * a , const void * b )
{
2024-07-14 18:56:31 +00:00
if ( ( ( const availdemo_t * ) a ) - > time < ( ( const availdemo_t * ) b ) - > time )
2017-09-20 11:27:13 +00:00
return 1 ;
2024-07-14 18:56:31 +00:00
if ( ( ( const availdemo_t * ) a ) - > time > ( ( const availdemo_t * ) b ) - > time )
2017-09-20 11:27:13 +00:00
return - 1 ;
2024-07-14 18:56:31 +00:00
if ( ( ( const availdemo_t * ) a ) - > smalltime < ( ( const availdemo_t * ) b ) - > smalltime )
2017-09-20 11:27:13 +00:00
return 1 ;
2024-07-14 18:56:31 +00:00
if ( ( ( const availdemo_t * ) a ) - > smalltime > ( ( const availdemo_t * ) b ) - > smalltime )
2017-09-20 11:27:13 +00:00
return - 1 ;
return 0 ;
}
void Cluster_BuildAvailableDemoList ( cluster_t * cluster )
{
cluster - > availdemoscount = 0 ;
# ifdef _WIN32
{
WIN32_FIND_DATA ffd ;
HANDLE h ;
char path [ 512 ] ;
snprintf ( path , sizeof ( path ) , " %s*.mvd " , cluster - > demodir ) ;
h = FindFirstFile ( path , & ffd ) ;
if ( h ! = INVALID_HANDLE_VALUE )
{
do
{
if ( cluster - > availdemoscount = = sizeof ( cluster - > availdemos ) / sizeof ( cluster - > availdemos [ 0 ] ) )
break ;
strlcpy ( cluster - > availdemos [ cluster - > availdemoscount ] . name , ffd . cFileName , sizeof ( cluster - > availdemos [ 0 ] . name ) ) ;
cluster - > availdemos [ cluster - > availdemoscount ] . size = ffd . nFileSizeLow ;
cluster - > availdemos [ cluster - > availdemoscount ] . time = ffd . ftLastWriteTime . dwHighDateTime ;
cluster - > availdemos [ cluster - > availdemoscount ] . smalltime = ffd . ftLastWriteTime . dwLowDateTime ;
cluster - > availdemoscount + + ;
} while ( FindNextFile ( h , & ffd ) ) ;
FindClose ( h ) ;
}
}
# else
{
DIR * dir ;
struct dirent * ent ;
struct stat sb ;
char fullname [ 512 ] ;
dir = opendir ( cluster - > demodir ) ; //yeek!
if ( dir )
{
for ( ; ; )
{
if ( cluster - > availdemoscount = = sizeof ( cluster - > availdemos ) / sizeof ( cluster - > availdemos [ 0 ] ) )
break ;
ent = readdir ( dir ) ;
if ( ! ent )
break ;
if ( * ent - > d_name = = ' . ' )
continue ; //ignore 'hidden' files
snprintf ( fullname , sizeof ( fullname ) , " %s%s " , cluster - > demodir , ent - > d_name ) ;
if ( stat ( fullname , & sb ) )
continue ; //some kind of error
strlcpy ( cluster - > availdemos [ cluster - > availdemoscount ] . name , ent - > d_name , sizeof ( cluster - > availdemos [ 0 ] . name ) ) ;
cluster - > availdemos [ cluster - > availdemoscount ] . size = sb . st_size ;
cluster - > availdemos [ cluster - > availdemoscount ] . time = sb . st_mtime ;
cluster - > availdemoscount + + ;
}
closedir ( dir ) ;
}
else
2020-01-20 18:01:39 +00:00
Sys_Printf ( cluster , " Couldn't open dir %s for demo listings \n " , cluster - > demodir ) ;
2017-09-20 11:27:13 +00:00
}
# endif
qsort ( cluster - > availdemos , cluster - > availdemoscount , sizeof ( cluster - > availdemos [ 0 ] ) , SortFilesByDate ) ;
}
void Cluster_Run ( cluster_t * cluster , qboolean dowait )
{
oproxy_t * pend , * pend2 , * pend3 ;
sv_t * sv , * old ;
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.
Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
tcpconnect_t * tc ;
2017-09-20 11:27:13 +00:00
int m ;
struct timeval timeout ;
fd_set socketset ;
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.
Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
fd_set socketset_wr ;
2017-09-20 11:27:13 +00:00
if ( dowait )
{
2021-05-09 13:02:23 +00:00
//FIXME: use poll or epoll to work around FD_SETSIZE limits, though we're mostly only doing this for the sleeping.
2017-09-20 11:27:13 +00:00
FD_ZERO ( & socketset ) ;
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.
Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
FD_ZERO ( & socketset_wr ) ;
2017-09-20 11:27:13 +00:00
m = 0 ;
if ( cluster - > qwdsocket [ 0 ] ! = INVALID_SOCKET )
{
2021-05-09 13:02:23 +00:00
if ( cluster - > qwdsocket [ 0 ] < FD_SETSIZE )
{
FD_SET ( cluster - > qwdsocket [ 0 ] , & socketset ) ;
if ( cluster - > qwdsocket [ 0 ] > = m )
m = cluster - > qwdsocket [ 0 ] + 1 ;
}
2010-03-14 14:35:56 +00:00
}
if ( cluster - > qwdsocket [ 1 ] ! = INVALID_SOCKET )
{
2021-05-09 13:02:23 +00:00
if ( cluster - > qwdsocket [ 1 ] < FD_SETSIZE )
{
FD_SET ( cluster - > qwdsocket [ 1 ] , & socketset ) ;
if ( cluster - > qwdsocket [ 1 ] > = m )
m = cluster - > qwdsocket [ 1 ] + 1 ;
}
2017-09-20 11:27:13 +00:00
}
for ( sv = cluster - > servers ; sv ; sv = sv - > next )
{
if ( sv - > usequakeworldprotocols & & sv - > sourcesock ! = INVALID_SOCKET )
{
2021-05-09 13:02:23 +00:00
if ( sv - > sourcesock > = FD_SETSIZE )
continue ; //panic...
2017-09-20 11:27:13 +00:00
FD_SET ( sv - > sourcesock , & socketset ) ;
if ( sv - > sourcesock > = m )
m = sv - > sourcesock + 1 ;
}
}
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.
Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
for ( tc = cluster - > tcpconnects ; tc ; tc = tc - > next )
{
if ( tc - > sock ! = INVALID_SOCKET & & tc - > sock < FD_SETSIZE )
{
FD_SET ( tc - > sock , & socketset ) ;
if ( tc - > sock > = m )
m = tc - > sock + 1 ;
}
}
2024-07-14 18:56:31 +00:00
TURN_AddFDs ( cluster , & socketset , & m ) ;
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.
Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
for ( pend = cluster - > pendingproxies ; pend ; pend = pend - > next )
{
if ( pend - > sock ! = INVALID_SOCKET & & pend - > sock < FD_SETSIZE )
{
FD_SET ( pend - > sock , & socketset ) ;
if ( pend - > file ) //also wake up if we're doing some (large) file transfer and we can give them a bit more.
FD_SET ( pend - > sock , & socketset_wr ) ;
if ( pend - > sock > = m )
m = pend - > sock + 1 ;
}
}
2017-09-20 11:27:13 +00:00
# ifndef _WIN32
# ifndef STDIN
# define STDIN 0
# endif
FD_SET ( STDIN , & socketset ) ;
if ( STDIN > = m )
m = STDIN + 1 ;
# endif
if ( cluster - > viewserver )
{
timeout . tv_sec = 0 ;
timeout . tv_usec = 1000 ;
}
else
{
timeout . tv_sec = 10 / 1000 ;
timeout . tv_usec = ( 100 % 1000 ) * 1000 ;
}
Added sys_openfile console command(and menu option) to web and flatpak(via cmake+dbus) builds, to 'install' packages on sandboxed systems a bit more easily.
Cmake: Add FTE_WERROR option, defaults to true in debug builds and off in release builds (in case future compilers have issues).
Cmake: Pull in libXscreensaver so we don't get interrupted by screensavers when playing demos.
Make: Added `make webcl-rel` for a web build without server bloat (eg for sites focused on demo playback. Yes, this means you XantoM).
fteqcc: Include the decompiler in fteqcc (non-gui) builds ('-d' arg).
fteqcc: Decompiler can now mostly handle hexen2 mods without any unknown opcodes.
Allow ezHud and OpenSSL to be compiled as in-engine plugins, potentially for web and windows ports respectively.
Web: Fix support for ogg vorbis. Add support for voip.
Web: Added basic support for WebXR.
QTV: Don't try seeking on unseekable qtv streams. Don't spam when developer 1 is set.
QTV: add support for some eztv extensions.
MVD: added hack to use ktx's vweps in mvd where mvdsv doesn't bother to record the info.
qwfwd: hack around a hack in qwfwd, allowing it to work again.
recording: favour qwd in single player, instead of mvd.
Protocol: reduce client memory used for precache names. Bump maximum precache counts - some people are just abusive, yes you Orl.
hexen2: add enough clientside protocol compat to play the demo included with h2mp. lacks effects.
in_xflip: restored this setting.
fs_hidesyspaths: new cvar, defaults to enabled so you won't find your username or whatever turning up in screenshots or the like. change it to 0 before debuging stuff eg via 'path'.
gl_overbright_models: Added cvar to match QS.
netchan: Added MTU determination, we'll no longer fail to connect when routers stupidly drop icmp packets.
Win: try a few other versions of xinput too.
CSQC: Added a CSQC_GenerateMaterial function, to give the csqc a chance to generate custom materials.
MenuQC: Added support for the skeletal objects API.
2024-04-09 17:13:59 +00:00
m = select ( m , & socketset , & socketset_wr , NULL , & timeout ) ;
2017-09-20 11:27:13 +00:00
# ifdef _WIN32
for ( ; ; )
{
char buffer [ 8192 ] ;
char * result ;
char c ;
if ( ! _kbhit ( ) )
break ;
c = _getch ( ) ;
if ( c = = ' \n ' | | c = = ' \r ' )
{
Sys_Printf ( cluster , " \n " ) ;
if ( cluster - > inputlength )
{
cluster - > commandinput [ cluster - > inputlength ] = ' \0 ' ;
result = Rcon_Command ( cluster , NULL , cluster - > commandinput , buffer , sizeof ( buffer ) , true ) ;
Sys_Printf ( cluster , " %s " , result ) ;
cluster - > inputlength = 0 ;
cluster - > commandinput [ 0 ] = ' \0 ' ;
}
}
else if ( c = = ' \b ' )
{
if ( cluster - > inputlength > 0 )
{
Sys_Printf ( cluster , " %c " , c ) ;
2019-02-16 19:09:07 +00:00
Sys_Printf ( cluster , " " ) ;
2017-09-20 11:27:13 +00:00
Sys_Printf ( cluster , " %c " , c ) ;
cluster - > inputlength - - ;
cluster - > commandinput [ cluster - > inputlength ] = ' \0 ' ;
}
}
else
{
Sys_Printf ( cluster , " %c " , c ) ;
if ( cluster - > inputlength < sizeof ( cluster - > commandinput ) - 1 )
{
cluster - > commandinput [ cluster - > inputlength + + ] = c ;
cluster - > commandinput [ cluster - > inputlength ] = ' \0 ' ;
}
}
}
# else
if ( FD_ISSET ( STDIN , & socketset ) )
{
char buffer [ 8192 ] ;
char * result ;
2020-02-11 18:06:10 +00:00
cluster - > inputlength = read ( STDIN , cluster - > commandinput , sizeof ( cluster - > commandinput ) ) ;
2017-09-20 11:27:13 +00:00
if ( cluster - > inputlength > = 1 )
{
cluster - > commandinput [ cluster - > inputlength - 1 ] = 0 ; // rip off the /n and terminate
cluster - > inputlength - - ;
if ( cluster - > inputlength )
{
cluster - > commandinput [ cluster - > inputlength ] = ' \0 ' ;
result = Rcon_Command ( cluster , NULL , cluster - > commandinput , buffer , sizeof ( buffer ) , true ) ;
printf ( " %s " , result ) ;
cluster - > inputlength = 0 ;
cluster - > commandinput [ 0 ] = ' \0 ' ;
}
}
}
# endif
}
cluster - > curtime = Sys_Milliseconds ( ) ;
for ( sv = cluster - > servers ; sv ; )
{
old = sv ;
sv = sv - > next ;
QTV_Run ( old ) ;
}
2024-07-14 18:56:31 +00:00
TURN_CheckFDs ( cluster ) ;
2010-03-14 14:35:56 +00:00
SV_FindProxies ( cluster - > tcpsocket [ 0 ] , cluster , NULL ) ; //look for any other proxies wanting to muscle in on the action.
2017-09-20 11:27:13 +00:00
SV_FindProxies ( cluster - > tcpsocket [ 1 ] , cluster , NULL ) ; //look for any other proxies wanting to muscle in on the action.
QW_UpdateUDPStuff ( cluster ) ;
while ( cluster - > pendingproxies )
{
pend2 = cluster - > pendingproxies - > next ;
if ( SV_ReadPendingProxy ( cluster , cluster - > pendingproxies ) )
cluster - > pendingproxies = pend2 ;
else
break ;
}
if ( cluster - > pendingproxies )
{
for ( pend = cluster - > pendingproxies ; pend & & pend - > next ; )
{
pend2 = pend - > next ;
pend3 = pend2 - > next ;
if ( SV_ReadPendingProxy ( cluster , pend2 ) )
{
pend - > next = pend3 ;
pend = pend3 ;
}
else
{
pend = pend2 ;
}
}
}
}
void DoCommandLine ( cluster_t * cluster , int argc , char * * argv )
{
int i ;
char commandline [ 8192 ] ;
char * result ;
char * arg ;
char buffer [ 8192 ] ;
//exec the - commands
commandline [ 0 ] = ' \0 ' ;
for ( i = 1 ; i < = argc ; i + + )
{
if ( i = = argc )
arg = " " ;
else
{
arg = argv [ i ] ;
if ( ! arg ) //NeXT can do this supposedly
arg = " " ;
}
if ( i = = argc | | * arg = = ' + ' | | * arg = = ' - ' )
{
if ( commandline [ 0 ] = = ' - ' )
{
result = Rcon_Command ( cluster , NULL , commandline + 1 , buffer , sizeof ( buffer ) , true ) ;
Sys_Printf ( cluster , " %s " , result ) ;
}
commandline [ 0 ] = ' \0 ' ;
}
strcat ( commandline , arg ) ;
strcat ( commandline , " " ) ;
}
//exec the configs
result = Rcon_Command ( cluster , NULL , " exec qtv.cfg " , buffer , sizeof ( buffer ) , true ) ;
Sys_Printf ( cluster , " %s " , result ) ;
//exec the + commands
commandline [ 0 ] = ' \0 ' ;
for ( i = 1 ; i < = argc ; i + + )
{
if ( i = = argc )
arg = " " ;
else
{
arg = argv [ i ] ;
if ( ! arg ) //NeXT can do this supposedly
arg = " " ;
}
if ( i = = argc | | * arg = = ' + ' | | * arg = = ' - ' )
{
if ( commandline [ 0 ] = = ' + ' )
{
result = Rcon_Command ( cluster , NULL , commandline + 1 , buffer , sizeof ( buffer ) , true ) ;
Sys_Printf ( cluster , " %s " , result ) ;
}
commandline [ 0 ] = ' \0 ' ;
}
strcat ( commandline , arg ) ;
strcat ( commandline , " " ) ;
}
}
# ifndef LIBQTV
int main ( int argc , char * * argv )
{
cluster_t * cluster ;
// soundtest();
# ifdef SIGPIPE
signal ( SIGPIPE , SIG_IGN ) ;
# endif
# ifdef _WIN32
{
WSADATA discard ;
WSAStartup ( MAKEWORD ( 1 , 1 ) , & discard ) ;
}
# endif
cluster = malloc ( sizeof ( * cluster ) ) ;
if ( cluster )
{
2019-02-16 19:09:07 +00:00
int j ;
2017-09-20 11:27:13 +00:00
memset ( cluster , 0 , sizeof ( * cluster ) ) ;
2019-02-16 19:09:07 +00:00
for ( j = 0 ; j < SOCKETGROUPS ; j + + )
{
cluster - > qwdsocket [ j ] = INVALID_SOCKET ;
cluster - > tcpsocket [ j ] = INVALID_SOCKET ;
}
2017-09-20 11:27:13 +00:00
cluster - > anticheattime = 1 * 1000 ;
cluster - > tooslowdelay = 100 ;
cluster - > qwlistenportnum = 0 ;
cluster - > allownqclients = true ;
strcpy ( cluster - > hostname , DEFAULT_HOSTNAME ) ;
cluster - > maxproxies = - 1 ;
2024-07-14 18:56:31 +00:00
//master protocol setup
cluster - > protocolname = strdup ( " FTE-Quake " ) ;
cluster - > protocolver = 3 ;
strlcpy ( cluster - > master , " master.frag-net.com:27950 " , sizeof ( cluster - > master ) ) ; //default to eukara's master server.
cluster - > mastersendtime = cluster - > curtime ;
cluster - > relayenabled = true ; //allow qtv
cluster - > pingtreeenabled = false ; //spammy.
cluster - > turnenabled = false ; //leave turn off by default. we need to know a usable inbound port range, we can't depend on just outgoing ephemerial ones. misconfigured relays will result in failures so don't default this to on.
# ifdef HAVE_EPOLL
cluster - > epfd = epoll_create1 ( 0 ) ;
# endif
2017-09-20 11:27:13 +00:00
strcpy ( cluster - > demodir , " qw/demos/ " ) ;
2018-04-06 17:39:32 +00:00
Sys_Printf ( cluster , " QTV " QTV_VERSION_STRING " \n " ) ;
2017-09-20 11:27:13 +00:00
DoCommandLine ( cluster , argc , argv ) ;
if ( ! cluster - > numservers )
{ //probably running on a home user's computer
2019-02-16 19:09:07 +00:00
if ( cluster - > qwdsocket [ SG_IPV4 ] = = INVALID_SOCKET & & cluster - > qwdsocket [ SG_IPV6 ] = = INVALID_SOCKET & & ! cluster - > qwlistenportnum )
2010-03-14 14:35:56 +00:00
{
cluster - > qwlistenportnum = 27599 ;
2019-02-16 19:09:07 +00:00
NET_InitUDPSocket ( cluster , cluster - > qwlistenportnum , SG_IPV6 ) ;
NET_InitUDPSocket ( cluster , cluster - > qwlistenportnum , SG_IPV4 ) ;
2017-09-20 11:27:13 +00:00
}
2019-02-16 19:09:07 +00:00
if ( cluster - > tcpsocket [ SG_IPV4 ] = = INVALID_SOCKET & & cluster - > tcpsocket [ SG_IPV6 ] = = INVALID_SOCKET & & ! cluster - > tcplistenportnum )
2010-03-14 14:35:56 +00:00
{
cluster - > tcplistenportnum = 27599 ;
2019-02-16 19:09:07 +00:00
Net_TCPListen ( cluster , cluster - > tcplistenportnum , SG_IPV6 ) ;
Net_TCPListen ( cluster , cluster - > tcplistenportnum , SG_IPV4 ) ;
2017-09-20 11:27:13 +00:00
}
2019-02-16 19:09:07 +00:00
Net_TCPListen ( cluster , 1 , SG_UNIX ) ;
2017-09-20 11:27:13 +00:00
Sys_Printf ( cluster , " \n "
2024-07-14 18:56:31 +00:00
" Welcome to QTV \n "
2017-09-20 11:27:13 +00:00
" Please type \n "
" qtv server:port \n "
" to connect to a tcp server. \n "
" qw server:port \n "
" to connect to a regular qw server. \n "
" demo qw/example.mvd \n "
" to play a demo from an mvd. \n "
" \n " ) ;
}
// Cluster_BuildAvailableDemoList(cluster);
while ( ! cluster - > wanttoexit )
{
Cluster_Run ( cluster , true ) ;
# ifdef VIEWER
DemoViewer_Update ( cluster - > viewserver ) ;
# endif
}
free ( cluster ) ;
}
return 0 ;
}
# endif
void QTV_Printf ( sv_t * qtv , char * fmt , . . . )
{
va_list argptr ;
char string [ 2048 ] ;
va_start ( argptr , fmt ) ;
vsnprintf ( string , sizeof ( string ) - 1 , fmt , argptr ) ;
string [ sizeof ( string ) - 1 ] = 0 ;
va_end ( argptr ) ;
if ( qtv - > silentstream )
return ;
Sys_Printf ( qtv - > cluster , " %s " , string ) ;
}
//#ifdef LIBQTV
//#ifndef _WIN32
//#define _cdecl
//#endif
//void _cdecl Con_Printf(char *fmt, ...);
//#endif
void Sys_Printf ( cluster_t * cluster , char * fmt , . . . )
{
va_list argptr ;
char string [ 2048 ] ;
unsigned char * t ;
va_start ( argptr , fmt ) ;
vsnprintf ( string , sizeof ( string ) - 1 , fmt , argptr ) ;
string [ sizeof ( string ) - 1 ] = 0 ;
va_end ( argptr ) ;
//#ifdef LIBQTV
// Con_Printf("QTV: %s", string);
//#endif
for ( t = ( unsigned char * ) string ; * t ; t + + )
{
if ( * t > = 146 & & * t < 156 )
* t = * t - 146 + ' 0 ' ;
if ( * t = = 143 )
* t = ' . ' ;
if ( * t = = 157 | | * t = = 158 | | * t = = 159 )
* t = ' - ' ;
if ( * t > = 128 )
* t - = 128 ;
if ( * t = = 16 )
* t = ' [ ' ;
if ( * t = = 17 )
* t = ' ] ' ;
if ( * t = = 29 )
* t = ' - ' ;
if ( * t = = 30 )
* t = ' - ' ;
if ( * t = = 31 )
* t = ' - ' ;
if ( * t = = ' \a ' ) //doh. :D
* t = ' ' ;
}
printf ( " %s " , string ) ;
}
2009-07-07 23:40:06 +00:00
//FIXME: move this to an appropriate place
# ifdef _WIN32
void Sys_mkdir ( char * name )
{
_mkdir ( name ) ;
}
# elif defined(__linux__)
void Sys_mkdir ( char * name )
{
mkdir ( name , 0777 ) ;
}
# else
# warning no Sys_mkdir function defined, hope the default works for you
void Sys_mkdir ( char * name )
{
mkdir ( name , 0777 ) ;
}
# endif
void QTV_mkdir ( char * path )
{
char * ofs ;
for ( ofs = path + 1 ; * ofs ; ofs + + )
{
if ( * ofs = = ' / ' )
{ // create the directory
* ofs = 0 ;
Sys_mkdir ( path ) ;
* ofs = ' / ' ;
}
}
}
/*
unsigned char * FS_ReadFile2 ( char * gamedir , char * filename , unsigned int * sizep )
{
int size ;
unsigned char * data ;
FILE * f ;
char fname [ 1024 ] ;
if ( ! * filename )
return NULL ;
//try and read it straight out of the file system
sprintf ( fname , " %s/%s " , gamedir , filename ) ;
f = fopen ( fname , " rb " ) ;
if ( ! f )
f = fopen ( filename , " rb " ) ; //see if we're being run from inside the gamedir
if ( ! f )
{
f = FindInPaks ( gamedir , filename , & size ) ;
if ( ! f )
f = FindInPaks ( " id1 " , filename , & size ) ;
if ( ! f )
{
return NULL ;
}
}
else
{
fseek ( f , 0 , SEEK_END ) ;
size = ftell ( f ) ;
fseek ( f , 0 , SEEK_SET ) ;
}
data = malloc ( size ) ;
if ( data )
fread ( data , 1 , size , f ) ;
fclose ( f ) ;
if ( sizep )
* sizep = size ;
return data ;
}
unsigned char * FS_ReadFile ( char * gamedir , char * filename , unsigned int * size )
{
char * data ;
if ( ! gamedir | | ! * gamedir | | ! strcmp ( gamedir , " qw " ) )
data = NULL ;
else
data = FS_ReadFile2 ( gamedir , filename , size ) ;
if ( ! data )
{
data = FS_ReadFile2 ( " qw " , filename , size ) ;
if ( ! data )
{
data = FS_ReadFile2 ( " id1 " , filename , size ) ;
if ( ! data )
{
return NULL ;
}
}
}
return data ;
}
void Cluster_Run ( cluster_t * cluster , qboolean dowait )
{
oproxy_t * pend , * pend2 , * pend3 ;
sv_t * sv , * old ;
int m ;
struct timeval timeout ;
fd_set socketset ;
if ( dowait )
{
FD_ZERO ( & socketset ) ;
m = 0 ;
if ( cluster - > qwdsocket ! = INVALID_SOCKET )
{
FD_SET ( cluster - > qwdsocket , & socketset ) ;
if ( cluster - > qwdsocket > = m )
m = cluster - > qwdsocket + 1 ;
}
for ( sv = cluster - > servers ; sv ; sv = sv - > next )
{
if ( sv - > usequkeworldprotocols & & sv - > sourcesock ! = INVALID_SOCKET )
{
FD_SET ( sv - > sourcesock , & socketset ) ;
if ( sv - > sourcesock > = m )
m = sv - > sourcesock + 1 ;
}
}
# ifndef _WIN32
# ifndef STDIN
# define STDIN 0
# endif
FD_SET ( STDIN , & socketset ) ;
if ( STDIN > = m )
m = STDIN + 1 ;
# endif
if ( cluster - > viewserver )
{
timeout . tv_sec = 0 ;
timeout . tv_usec = 1000 ;
}
else
{
timeout . tv_sec = 100 / 1000 ;
timeout . tv_usec = ( 100 % 1000 ) * 1000 ;
}
m = select ( m , & socketset , NULL , NULL , & timeout ) ;
# ifdef _WIN32
for ( ; ; )
{
char buffer [ 8192 ] ;
char * result ;
char c ;
if ( ! _kbhit ( ) )
break ;
c = _getch ( ) ;
if ( c = = ' \n ' | | c = = ' \r ' )
{
Sys_Printf ( cluster , " \n " ) ;
if ( cluster - > inputlength )
{
cluster - > commandinput [ cluster - > inputlength ] = ' \0 ' ;
result = Rcon_Command ( cluster , NULL , cluster - > commandinput , buffer , sizeof ( buffer ) , true ) ;
Sys_Printf ( cluster , " %s " , result ) ;
cluster - > inputlength = 0 ;
cluster - > commandinput [ 0 ] = ' \0 ' ;
}
}
else if ( c = = ' \b ' )
{
if ( cluster - > inputlength > 0 )
{
Sys_Printf ( cluster , " %c " , c ) ;
Sys_Printf ( cluster , " " , c ) ;
Sys_Printf ( cluster , " %c " , c ) ;
cluster - > inputlength - - ;
cluster - > commandinput [ cluster - > inputlength ] = ' \0 ' ;
}
}
else
{
Sys_Printf ( cluster , " %c " , c ) ;
if ( cluster - > inputlength < sizeof ( cluster - > commandinput ) - 1 )
{
cluster - > commandinput [ cluster - > inputlength + + ] = c ;
cluster - > commandinput [ cluster - > inputlength ] = ' \0 ' ;
}
}
}
# else
if ( FD_ISSET ( STDIN , & socketset ) )
{
char buffer [ 8192 ] ;
char * result ;
cluster - > inputlength = read ( 0 , cluster - > commandinput , sizeof ( cluster - > commandinput ) ) ;
if ( cluster - > inputlength > = 1 )
{
cluster - > commandinput [ cluster - > inputlength - 1 ] = 0 ; // rip off the /n and terminate
cluster - > inputlength - - ;
if ( cluster - > inputlength )
{
cluster - > commandinput [ cluster - > inputlength ] = ' \0 ' ;
result = Rcon_Command ( cluster , NULL , cluster - > commandinput , buffer , sizeof ( buffer ) , true ) ;
printf ( " %s " , result ) ;
cluster - > inputlength = 0 ;
cluster - > commandinput [ 0 ] = ' \0 ' ;
}
}
}
# endif
}
cluster - > curtime = Sys_Milliseconds ( ) ;
for ( sv = cluster - > servers ; sv ; )
{
old = sv ;
sv = sv - > next ;
QTV_Run ( old ) ;
}
SV_FindProxies ( cluster - > tcpsocket , cluster , NULL ) ; //look for any other proxies wanting to muscle in on the action.
QW_UpdateUDPStuff ( cluster ) ;
while ( cluster - > pendingproxies )
{
pend2 = cluster - > pendingproxies - > next ;
if ( SV_ReadPendingProxy ( cluster , cluster - > pendingproxies ) )
cluster - > pendingproxies = pend2 ;
else
break ;
}
if ( cluster - > pendingproxies )
{
for ( pend = cluster - > pendingproxies ; pend & & pend - > next ; )
{
pend2 = pend - > next ;
pend3 = pend2 - > next ;
if ( SV_ReadPendingProxy ( cluster , pend2 ) )
{
pend - > next = pend3 ;
pend = pend3 ;
}
else
{
pend = pend2 ;
}
}
}
}
*/