diff --git a/engine/common/common.h b/engine/common/common.h index e2d83840..1ac016dc 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -946,6 +946,7 @@ void XRcon_Init( void ); void XRcon_Shutdown( void ); void XRcon_Frame( void ); void XRcon_Print( const char *msg ); +qboolean XRcon_IsActive( void ); #ifdef REF_DLL #error "common.h in ref_dll" diff --git a/engine/common/sys_con.c b/engine/common/sys_con.c index 6c126b86..85c70229 100644 --- a/engine/common/sys_con.c +++ b/engine/common/sys_con.c @@ -167,7 +167,6 @@ void Sys_CloseLog( const char *finalmsg ) s_ld.logfile = NULL; } -#if XASH_COLORIZE_CONSOLE static qboolean Sys_WriteEscapeSequenceForColorcode( int fd, int c ) { static const char *q3ToAnsi[ 8 ] = @@ -185,14 +184,8 @@ static qboolean Sys_WriteEscapeSequenceForColorcode( int fd, int c ) return write( fd, esc, c == 7 ? 4 : 7 ) < 0 ? false : true; } -#else -static qboolean Sys_WriteEscapeSequenceForColorcode( int fd, int c ) -{ - return true; -} -#endif -static void Sys_PrintLogfile( const int fd, const char *logtime, size_t logtime_len, const char *msg, const int colorize ) +static void Sys_PrintLogfile( const int fd, const char *logtime, size_t logtime_len, const char *msg, qboolean colorize ) { const char *p = msg; @@ -204,6 +197,17 @@ static void Sys_PrintLogfile( const int fd, const char *logtime, size_t logtime_ } } + if( !colorize ) + { + if( write( fd, msg, Q_strlen( msg )) < 0 ) + { + // don't call engine Msg, might cause recursion + fprintf( stderr, "%s: write failed: %s\n", __func__, strerror( errno )); + } + + return; + } + while( p && *p ) { p = Q_strchr( msg, '^' ); @@ -226,8 +230,7 @@ static void Sys_PrintLogfile( const int fd, const char *logtime, size_t logtime_ } msg = p + 2; - if( colorize ) - Sys_WriteEscapeSequenceForColorcode( fd, ColorIndex( p[1] )); + Sys_WriteEscapeSequenceForColorcode( fd, ColorIndex( p[1] )); } else { @@ -238,73 +241,89 @@ static void Sys_PrintLogfile( const int fd, const char *logtime, size_t logtime_ } // flush the color - if( colorize ) - Sys_WriteEscapeSequenceForColorcode( fd, 7 ); + Sys_WriteEscapeSequenceForColorcode( fd, 7 ); } -static void Sys_PrintStdout( const char *logtime, size_t logtime_len, const char *msg ) +static void Sys_WriteLogfile( int fd, const char *logtime, size_t logtime_len, const char *msg ) { -#if XASH_MOBILE_PLATFORM - static char buf[MAX_PRINT_MSG]; + if( logtime_len != 0 ) + { + if( write( fd, logtime, logtime_len ) < 0 ) + { + // not critical for us + } + } - // strip color codes - COM_StripColors( msg, buf ); +} - // platform-specific output +static void Sys_PrintStdout( const char *logtime, size_t logtime_len, const char *msg, const char *stripped ) +{ #if XASH_ANDROID && !XASH_DEDICATED - __android_log_write( ANDROID_LOG_INFO, "Xash", buf ); + __android_log_write( ANDROID_LOG_INFO, "Xash", stripped ); #endif // XASH_ANDROID && !XASH_DEDICATED #if TARGET_OS_IOS void IOS_Log( const char * ); - IOS_Log( buf ); + IOS_Log( stripped ); #endif // TARGET_OS_IOS #if XASH_NSWITCH && NSWITCH_DEBUG // just spew it to stderr normally in debug mode - fprintf( stderr, "%s %s", logtime, buf ); + fprintf( stderr, "%s %s", logtime, stripped ); #endif // XASH_NSWITCH && NSWITCH_DEBUG #if XASH_PSVITA // spew to stderr only in developer mode if( host_developer.value ) { - fprintf( stderr, "%s %s", logtime, buf ); + fprintf( stderr, "%s %s", logtime, stripped ); } #endif -#elif !XASH_WIN32 // Wcon does the job - Sys_PrintLogfile( STDOUT_FILENO, logtime, logtime_len, msg, XASH_COLORIZE_CONSOLE ); +#if !XASH_MOBILE_PLATFORM && !XASH_WIN32 // Wcon does the job + Sys_PrintLogfile( STDOUT_FILENO, logtime, logtime_len, XASH_COLORIZE_CONSOLE ? msg : stripped, XASH_COLORIZE_CONSOLE ); Sys_FlushStdout(); #endif + + XRcon_Print( stripped ); } void Sys_PrintLog( const char *pMsg ) { - const struct tm *crt_tm = NULL; - char logtime[32] = ""; static char lastchar; - qboolean print_time = false; - size_t logtime_len = 0; + const struct tm *crt_tm = NULL; if( !lastchar || lastchar == '\n' ) { time_t crt_time; if( time( &crt_time ) >= 0 ) - { crt_tm = localtime( &crt_time ); - print_time = crt_tm != NULL; - } } - if( print_time ) + char logtime[32] = ""; + size_t logtime_len = 0; + if( crt_tm != NULL ) { logtime_len = strftime( logtime, sizeof( logtime ), "[%H:%M:%S] ", crt_tm ); // short time logtime_len = Q_min( logtime_len, sizeof( logtime ) - 1 ); // just in case } +#if !XASH_WIN32 && !XASH_COLORIZE_CONSOLE + qboolean need_strip = true; // stdout sink can't render ^N, must strip first +#else + qboolean need_strip = s_ld.logfile != NULL || XRcon_IsActive(); +#endif + + const char *log_msg = pMsg; + if( need_strip ) + { + static char stripped[MAX_PRINT_MSG]; + COM_StripColors( pMsg, stripped ); + log_msg = stripped; + } + // spew to stdout - Sys_PrintStdout( logtime, logtime_len, pMsg ); + Sys_PrintStdout( logtime, logtime_len, pMsg, log_msg ); size_t len = Q_strlen( pMsg ); @@ -314,7 +333,7 @@ void Sys_PrintLog( const char *pMsg ) // spew to engine.log if( s_ld.logfile ) { - if( s_ld.log_time && print_time ) + if( s_ld.log_time && crt_tm != NULL ) { logtime_len = strftime( logtime, sizeof( logtime ), "[%Y:%m:%d|%H:%M:%S] ", crt_tm ); //full time logtime_len = Q_min( logtime_len, sizeof( logtime ) - 1 ); // just in case @@ -325,7 +344,7 @@ void Sys_PrintLog( const char *pMsg ) logtime_len = 0; } - Sys_PrintLogfile( s_ld.logfileno, logtime, logtime_len, pMsg, false ); + Sys_WriteLogfile( s_ld.logfileno, logtime, logtime_len, log_msg ); Sys_FlushLogfile(); } } diff --git a/engine/common/system.c b/engine/common/system.c index 1eea80c9..92aa2e4a 100644 --- a/engine/common/system.c +++ b/engine/common/system.c @@ -517,7 +517,6 @@ void Sys_Print( const char *pMsg ) Sys_PrintLog( pMsg ); Rcon_Print( &host.rd, pMsg ); - XRcon_Print( pMsg ); } /* diff --git a/engine/common/xrcon.c b/engine/common/xrcon.c index 90c67240..054fb735 100644 --- a/engine/common/xrcon.c +++ b/engine/common/xrcon.c @@ -38,6 +38,8 @@ GNU General Public License for more details. static CVAR_DEFINE_AUTO( xrcon_enable, "0", FCVAR_PRIVILEGED, "enable remote console access server" ); static CVAR_DEFINE_AUTO( xrcon_address, "127.0.0.1:27000", FCVAR_PRIVILEGED, "XRCON server bind address and port" ); +static CVAR_DEFINE_AUTO( xrcon_flush_interval, "0.05", FCVAR_PRIVILEGED, "seconds between flushes of pending console output to the XRCON client" ); +static CVAR_DEFINE_AUTO( xrcon_retry_delay, "5.0", FCVAR_PRIVILEGED, "seconds to wait before retrying to bind the XRCON listen socket after a failure" ); typedef enum { @@ -368,9 +370,8 @@ static void XRcon_HandleDataTx( void ) { int err = WSAGetLastError(); if( err != WSAEWOULDBLOCK && err != WSAEALREADY ) - { XRcon_DisconnectClient(); - } + return; } @@ -516,7 +517,7 @@ static void XRcon_UpdateConnected( void ) if( xrcon.print_pos > 0 && Platform_DoubleTime() >= xrcon.print_flush_time ) { XRcon_FlushPrintBuffer(); - xrcon.print_flush_time = Platform_DoubleTime() + XRCON_FLUSH_INTERVAL; + xrcon.print_flush_time = Platform_DoubleTime() + xrcon_flush_interval.value; } } @@ -526,7 +527,7 @@ static void XRcon_UpdateIdle( void ) return; XRcon_StartListening(); - xrcon.retry_timeout = Platform_DoubleTime() + XRCON_RETRY_DELAY; + xrcon.retry_timeout = Platform_DoubleTime() + xrcon_retry_delay.value; } void XRcon_Print( const char *msg ) @@ -534,63 +535,29 @@ void XRcon_Print( const char *msg ) if( xrcon.state != XRCON_STATE_CONNECTED ) return; - if( !msg || !*msg ) + if( !msg ) return; - const char *p = msg; - while( p && *p ) + while( *msg ) { - p = Q_strpbrk( msg, "^\n\r" ); - if( p == NULL ) - { - size_t length = Q_strlen( msg ); - if( xrcon.print_pos + length < sizeof( xrcon.print_buffer ) - 1 ) - { - memcpy( xrcon.print_buffer + xrcon.print_pos, msg, length ); - xrcon.print_pos += length; - } - break; - } - else if( *p == '\n' || *p == '\r' ) - { - size_t length = p - msg; - if( xrcon.print_pos + length < sizeof( xrcon.print_buffer ) - 1 ) - { - memcpy( xrcon.print_buffer + xrcon.print_pos, msg, length ); - xrcon.print_pos += length; - } + const char *p = Q_strchrnul( msg, '\n' ); + size_t length = p - msg; - if( xrcon.print_pos > 0 ) - { - XRcon_FlushPrintBuffer(); - xrcon.print_flush_time = Platform_DoubleTime() + XRCON_FLUSH_INTERVAL; - } - msg = p + 1; - } - else if( IsColorString( p )) + if( xrcon.print_pos + length < sizeof( xrcon.print_buffer ) - 1 ) { - if( p != msg ) - { - size_t length = p - msg; - if( xrcon.print_pos + length < sizeof( xrcon.print_buffer ) - 1 ) - { - memcpy( xrcon.print_buffer + xrcon.print_pos, msg, length ); - xrcon.print_pos += length; - } - - } - msg = p + 2; + memcpy( xrcon.print_buffer + xrcon.print_pos, msg, length ); + xrcon.print_pos += length; } - else + + if( *p == '\0' ) + return; + + if( xrcon.print_pos > 0 ) { - size_t length = p - msg + 1; - if( xrcon.print_pos + length < sizeof( xrcon.print_buffer ) - 1 ) - { - memcpy( xrcon.print_buffer + xrcon.print_pos, msg, length ); - xrcon.print_pos += length; - } - msg = p + 1; + XRcon_FlushPrintBuffer(); + xrcon.print_flush_time = Platform_DoubleTime() + xrcon_flush_interval.value; } + msg = p + 1; } } @@ -649,6 +616,8 @@ void XRcon_Init( void ) Cvar_RegisterVariable( &xrcon_enable ); Cvar_RegisterVariable( &xrcon_address ); + Cvar_RegisterVariable( &xrcon_flush_interval ); + Cvar_RegisterVariable( &xrcon_retry_delay ); NET_NetadrSetType( &xrcon.bindadr, NA_UNDEFINED ); } @@ -658,3 +627,8 @@ void XRcon_Shutdown( void ) XRcon_CloseListenSocket(); XRcon_SetState( XRCON_STATE_IDLE ); } + +qboolean XRcon_IsActive( void ) +{ + return xrcon.state == XRCON_STATE_CONNECTED; +}