diff options
author | Andrey Nazarov <skuller@skuller.net> | 2008-08-28 17:35:47 +0000 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2008-08-28 17:35:47 +0000 |
commit | 8d466c8c99a82c9fa87d2c8a932413da1ac89e04 (patch) | |
tree | 9954623456ae4dc245daa98f57f913f9892a742b | |
parent | 651dbdd53d61b75108ffdc95f3efdb285adc7170 (diff) |
Removed unimplemented `sv_mvd_wait' cvar.
Bind server TCP socket with SO_REUSEADDR option, close it properly on shutdown.
Implemented server console logging over HTTP, accessible at `/console' URI.
Added `sv_console_auth' cvar controlling access to server console.
Never allow server realtime go back.
Spectator chat on GTV is no longer audible.
Moved POV name on the very top of the screen.
-rw-r--r-- | source/cl_draw.c | 2 | ||||
-rw-r--r-- | source/cl_main.c | 6 | ||||
-rw-r--r-- | source/cl_public.h | 2 | ||||
-rw-r--r-- | source/common.c | 3 | ||||
-rw-r--r-- | source/mvd_game.c | 16 | ||||
-rw-r--r-- | source/net_common.c | 49 | ||||
-rw-r--r-- | source/sv_http.c | 74 | ||||
-rw-r--r-- | source/sv_local.h | 6 | ||||
-rw-r--r-- | source/sv_main.c | 45 | ||||
-rw-r--r-- | source/sv_mvd.c | 8 | ||||
-rw-r--r-- | source/sv_public.h | 3 | ||||
-rw-r--r-- | wiki/doc/server.mdwn | 26 |
12 files changed, 179 insertions, 61 deletions
diff --git a/source/cl_draw.c b/source/cl_draw.c index 13236e7..ba9c5c2 100644 --- a/source/cl_draw.c +++ b/source/cl_draw.c @@ -598,7 +598,7 @@ static void draw_following( void ) { x = ( scr_hudWidth - strlen( string ) * CHAR_WIDTH ) / 2; - R_DrawString( x, 48, 0, MAX_STRING_CHARS, string, scr_font ); + R_DrawString( x, 2, 0, MAX_STRING_CHARS, string, scr_font ); } static void draw_turtle( void ) { diff --git a/source/cl_main.c b/source/cl_main.c index 4b2c452..644940f 100644 --- a/source/cl_main.c +++ b/source/cl_main.c @@ -2641,9 +2641,9 @@ CL_Frame ================== */ -void CL_Frame( int msec ) { - static int ref_extra, phys_extra, main_extra; - int ref_msec, phys_msec; +void CL_Frame( unsigned msec ) { + static unsigned ref_extra, phys_extra, main_extra; + unsigned ref_msec, phys_msec; qboolean phys_frame, ref_frame; time_after_ref = time_before_ref = 0; diff --git a/source/cl_public.h b/source/cl_public.h index b6d9dac..42e07fc 100644 --- a/source/cl_public.h +++ b/source/cl_public.h @@ -51,7 +51,7 @@ void CL_ProcessEvents( void ); void CL_Init (void); void CL_Disconnect( comErrorType_t type, const char *text ); void CL_Shutdown (void); -void CL_Frame (int msec); +void CL_Frame (unsigned msec); void CL_LocalConnect( void ); void CL_RestartFilesystem( void ); void CL_Activate( active_t active ); diff --git a/source/common.c b/source/common.c index 0dc03b4..dad3b9d 100644 --- a/source/common.c +++ b/source/common.c @@ -284,6 +284,9 @@ void Com_Printf( const char *fmt, ... ) { // debugging console Sys_ConsoleOutput( msg ); + // remote console + SV_ConsoleOutput( msg ); + // logfile if( com_logFile ) { LogFile_Output( msg ); diff --git a/source/mvd_game.c b/source/mvd_game.c index a0d7018..9b10097 100644 --- a/source/mvd_game.c +++ b/source/mvd_game.c @@ -245,7 +245,7 @@ static void MVD_LayoutFollow( udpClient_t *client ) { // send the layout MSG_WriteByte( svc_layout ); - MSG_WriteString( va( "xv 0 yt 48 cstring \"%s\"", name ) ); + MSG_WriteString( va( "xv 0 yt 2 cstring \"%s\"", name ) ); SV_ClientAddMessage( client->cl, MSG_RELIABLE|MSG_CLEAR ); client->layout_time = svs.realtime; @@ -664,7 +664,8 @@ static void MVD_Say_f( udpClient_t *client ) { mvd_t *mvd = client->mvd; unsigned delta, delay = mvd_flood_waitdelay->value * 1000; unsigned treshold = mvd_flood_persecond->value * 1000; - char *text; + char text[150]; + size_t len; int i; if( mvd_flood_mute->integer && !client->admin ) { @@ -703,11 +704,14 @@ static void MVD_Say_f( udpClient_t *client ) { client->floodSamples[client->floodHead & FLOOD_MASK] = svs.realtime; client->floodHead++; - text = Cmd_Args(); - //text[128] = 0; // don't let it be too long + len = Com_sprintf( text, sizeof( text ), "[MVD] %s: %s", + client->cl->name, Cmd_Args() ); + for( i = 0; i < len; i++ ) { + text[i] |= 128; + } - MVD_BroadcastPrintf( mvd, PRINT_CHAT, client->admin ? 0 : UF_MUTE_OBSERVERS, - "[MVD] %s: %s\n", client->cl->name, text ); + MVD_BroadcastPrintf( mvd, PRINT_MEDIUM, client->admin ? + 0 : UF_MUTE_OBSERVERS, "%s\n", text ); } static void MVD_Observe_f( udpClient_t *client ) { diff --git a/source/net_common.c b/source/net_common.c index 3db96f8..eb8964b 100644 --- a/source/net_common.c +++ b/source/net_common.c @@ -677,10 +677,10 @@ fail: return INVALID_SOCKET; } -static SOCKET TCP_OpenSocket( const char *interface, int port ) { +static SOCKET TCP_OpenSocket( const char *interface, int port, netsrc_t who ) { SOCKET newsocket; struct sockaddr_in address; - u_long _true = 1; + u_long _true; if( !interface || !interface[0] ) { interface = "localhost"; @@ -695,10 +695,21 @@ static SOCKET TCP_OpenSocket( const char *interface, int port ) { } // make it non-blocking + _true = 1; if( ioctlsocket( newsocket, FIONBIO, &_true ) == -1 ) { goto fail; } + // give it a chance to reuse previous port + if( who == NS_SERVER ) { + _true = 1; + if( setsockopt( newsocket, SOL_SOCKET, SO_REUSEADDR, + ( char * )&_true, sizeof( _true ) ) == -1 ) + { + goto fail; + } + } + if( !NET_StringToIface( interface, &address ) ) { Com_Printf( "Bad interface address: %s\n", interface ); goto fail; @@ -797,7 +808,7 @@ neterr_t NET_Listen( qboolean arg ) { return NET_OK; } - tcp_socket = TCP_OpenSocket( net_ip->string, net_port->integer ); + tcp_socket = TCP_OpenSocket( net_ip->string, net_port->integer, NS_SERVER ); if( tcp_socket == INVALID_SOCKET ) { return NET_ERROR; } @@ -867,7 +878,7 @@ neterr_t NET_Connect( const netadr_t *peer, netstream_t *s ) { struct sockaddr_in address; int ret; - socket = TCP_OpenSocket( net_ip->string, net_clientport->integer ); + socket = TCP_OpenSocket( net_ip->string, net_clientport->integer, NS_CLIENT ); if( socket == INVALID_SOCKET ) { return NET_ERROR; } @@ -1065,6 +1076,21 @@ static void NET_DumpHostInfo( struct hostent *h ) { } } +static void dump_socket( SOCKET s, const char *s1, const char *s2 ) { + struct sockaddr_in sockaddr; + socklen_t len; + netadr_t adr; + + len = sizeof( sockaddr ); + if( getsockname( s, ( struct sockaddr * )&sockaddr, &len ) == -1 ) { + NET_GET_ERROR(); + Com_EPrintf( "%s: getsockname: %s\n", __func__, NET_ErrorString() ); + return; + } + NET_SockadrToNetadr( &sockaddr, &adr ); + Com_Printf( "%s %s socket bound to %s\n", s1, s2, NET_AdrToString( &adr ) ); +} + /* ==================== NET_ShowIP_f @@ -1073,17 +1099,16 @@ NET_ShowIP_f static void NET_ShowIP_f( void ) { char buffer[256]; struct hostent *h; - struct sockaddr_in address; - socklen_t length; - netadr_t adr; netsrc_t sock; if( gethostname( buffer, sizeof( buffer ) ) == -1 ) { + NET_GET_ERROR(); Com_EPrintf( "%s: gethostname: %s\n", __func__, NET_ErrorString() ); return; } if( !( h = gethostbyname( buffer ) ) ) { + NET_GET_ERROR(); Com_EPrintf( "%s: gethostbyname: %s\n", __func__, NET_ErrorString() ); return; } @@ -1092,14 +1117,12 @@ static void NET_ShowIP_f( void ) { for( sock = 0; sock < NS_COUNT; sock++ ) { if( udp_sockets[sock] != INVALID_SOCKET ) { - length = sizeof( address ); - getsockname( udp_sockets[sock], ( struct sockaddr * )&address, - &length ); - NET_SockadrToNetadr( &address, &adr ); - Com_Printf( "%s bound to %s\n", socketNames[sock], - NET_AdrToString( &adr ) ); + dump_socket( udp_sockets[sock], socketNames[sock], "UDP" ); } } + if( tcp_socket != INVALID_SOCKET ) { + dump_socket( tcp_socket, socketNames[NS_SERVER], "TCP" ); + } } /* diff --git a/source/sv_http.c b/source/sv_http.c index 0c2c5cf..37b0458 100644 --- a/source/sv_http.c +++ b/source/sv_http.c @@ -239,6 +239,75 @@ static void uri_mvdstream( const char *uri ) { } } +void SV_ConsoleOutput( const char *msg ) { + tcpClient_t *client; + char text[MAXPRINTMSG]; + char *p, *maxp; + size_t len; + int c; + + if( !svs.initialized ) { + return; + } + if( LIST_EMPTY( &svs.console_list ) ) { + return; + } + + p = text; + maxp = text + sizeof( text ) - 1; + while( *msg ) { + if( Q_IsColorString( msg ) ) { + msg += 2; + continue; + } + + if( p == maxp ) { + break; + } + + c = *msg++; + c &= 127; + + *p++ = c; + } + *p = 0; + + len = p - text; + + LIST_FOR_EACH( tcpClient_t, client, &svs.console_list, mvdEntry ) { + if( FIFO_Write( &client->stream.send, text, len ) != len ) { + SV_HttpDrop( client, "overflowed" ); + } + } +} + +static void uri_console( const char *uri ) { + char *auth = sv_console_auth->string; + char *cred = http_client->credentials; + + if( !auth[0] || !cred || strcmp( cred, auth ) ) { + strcpy( http_header, + "WWW-Authenticate: Basic realm=\"console\"\r\n" ); + SV_HttpReject( "401 Not Authorized", + "You are not authorized to access " + "console stream on this server." ); + return; + } + + if( http_client->method == HTTP_METHOD_HEAD ) { + SV_HttpPrintf( "HTTP/1.0 200 OK\r\n\r\n" ); + SV_HttpDrop( http_client, "200 OK " ); + return; + } + + SV_HttpPrintf( + "HTTP/1.0 200 OK\r\n" + "Content-Type: text/plain\r\n" + "\r\n" ); + List_Append( &svs.console_list, &http_client->mvdEntry ); + http_client->state = cs_spawned; +} + #if 0 static void uri_root( const char *uri ) { SV_HttpPrintf( "HTTP/1.0 200 OK\r\n" ); @@ -270,6 +339,7 @@ static const uriEntry_t rootURIs[] = { { "", uri_status }, { "status", uri_status }, { "mvdstream", uri_mvdstream }, + { "console", uri_console }, { NULL } }; @@ -716,6 +786,10 @@ void SV_HttpRun( void ) { // run network stream ret = NET_Run( &client->stream ); if( ret == NET_AGAIN ) { + // don't timeout + if( client->state >= cs_connected && !FIFO_Usage( &client->stream.send ) ) { + client->lastmessage = svs.realtime; + } continue; } if( ret != NET_OK ) { diff --git a/source/sv_local.h b/source/sv_local.h index 9c54aaf..cc10a92 100644 --- a/source/sv_local.h +++ b/source/sv_local.h @@ -80,6 +80,7 @@ typedef struct { int spawncount; // random number generated each server spawn int framenum; + unsigned frametime; char name[MAX_QPATH]; // map name, or cinematic name cm_t cm; @@ -352,8 +353,8 @@ typedef struct { } filtercmd_t; typedef struct server_static_s { - qboolean initialized; // sv_init has completed - unsigned realtime, time; // always increasing, no clamping, etc + qboolean initialized; // sv_init has completed + unsigned realtime; // always increasing, no clamping, etc int gameFeatures; @@ -429,6 +430,7 @@ extern cvar_t *sv_iplimit; extern cvar_t *sv_http_enable; extern cvar_t *sv_http_maxclients; extern cvar_t *sv_http_minclients; +extern cvar_t *sv_console_auth; extern cvar_t *sv_debug_send; extern cvar_t *sv_pad_packets; diff --git a/source/sv_main.c b/source/sv_main.c index e3bf43e..46e5aaf 100644 --- a/source/sv_main.c +++ b/source/sv_main.c @@ -61,6 +61,7 @@ cvar_t *sv_novis; cvar_t *sv_http_enable; cvar_t *sv_http_maxclients; cvar_t *sv_http_minclients; +cvar_t *sv_console_auth; cvar_t *sv_maxclients; cvar_t *sv_reserved_slots; @@ -1244,9 +1245,7 @@ void SV_ProcessEvents( void ) { // process loopback packets while( NET_GetLoopPacket( NS_SERVER ) ) { - if( sv_running->integer ) { - SV_PacketEvent( NET_OK ); - } + SV_PacketEvent( NET_OK ); } #endif @@ -1416,7 +1415,7 @@ static void SV_RunGameFrame( void ) { // compression can get confused when a client // has the "current" frame sv.framenum++; - svs.time += 100; + sv.frametime = 0; if( svs.mvd.dummy ) { SV_MvdBeginFrame(); @@ -1425,7 +1424,8 @@ static void SV_RunGameFrame( void ) { ge->RunFrame(); if( msg_write.cursize ) { - Com_WPrintf( "Game DLL left %"PRIz" bytes in multicast buffer, cleared.\n", + Com_WPrintf( "Game DLL left %"PRIz" bytes " + "in multicast buffer, cleared.\n", msg_write.cursize ); SZ_Clear( &msg_write ); } @@ -1435,13 +1435,6 @@ static void SV_RunGameFrame( void ) { SV_MvdEndFrame(); } - // never get more than one tic behind - if( svs.time < svs.realtime ) { - if( sv_showclamp->integer ) - Com_Printf( "sv highclamp\n" ); - svs.realtime = svs.time; - } - #if USE_CLIENT if( host_speeds->integer ) time_after_game = Sys_Milliseconds(); @@ -1520,7 +1513,7 @@ SV_Frame ================== */ -void SV_Frame( int msec ) { +void SV_Frame( unsigned msec ) { int mvdconns; #if USE_CLIENT @@ -1573,16 +1566,12 @@ void SV_Frame( int msec ) { SV_SendAsyncPackets(); // move autonomous things around if enough time has passed - if( !com_timedemo->integer && svs.realtime < svs.time ) { - // never let the time get too far off - if( svs.time - svs.realtime > 100 ) { - if( sv_showclamp->integer ) - Com_Printf( "sv lowclamp\n" ); - svs.realtime = svs.time - 100; - } - if( dedicated->integer ) { - NET_Sleep( svs.time - svs.realtime ); - } + sv.frametime += msec; + if( !com_timedemo->integer && sv.frametime < 100 ) { +#if USE_CLIENT + if( dedicated->integer ) +#endif + NET_Sleep( 100 - sv.frametime ); return; } @@ -1593,7 +1582,7 @@ void SV_Frame( int msec ) { SV_GiveMsec(); // let everything in the world think and move - SV_RunGameFrame(); + SV_RunGameFrame(); // send messages back to the clients that had packets read this frame SV_SendClientMessages(); @@ -1796,6 +1785,7 @@ void SV_Init( void ) { sv_http_enable = Cvar_Get( "sv_http_enable", "0", CVAR_LATCH ); sv_http_maxclients = Cvar_Get( "sv_http_maxclients", "4", 0 ); sv_http_minclients = Cvar_Get( "sv_http_minclients", "4", 0 ); + sv_console_auth = Cvar_Get( "sv_console_auth", "", 0 ); allow_download = Cvar_Get( "allow_download", "1", CVAR_ARCHIVE ); allow_download_players = Cvar_Get( "allow_download_players", "0", CVAR_ARCHIVE ); @@ -1899,7 +1889,6 @@ static void SV_FinalMessage( const char *message, int cmd ) { LIST_FOR_EACH( tcpClient_t, t, &svs.mvd.clients, mvdEntry ) { SV_HttpWrite( t, &length, 2 ); SV_HttpFinish( t ); - NET_Run( &t->stream ); } // free any data dynamically allocated @@ -1910,12 +1899,15 @@ static void SV_FinalMessage( const char *message, int cmd ) { SV_RemoveClient( client ); } + // drop any TCP clients, flushing pending data LIST_FOR_EACH_SAFE( tcpClient_t, t, tnext, &svs.tcp_client_list, entry ) { SV_HttpDrop( t, NULL ); + NET_Run( &t->stream ); NET_Close( &t->stream ); Z_Free( t ); } + // free cached TCP client slots LIST_FOR_EACH_SAFE( tcpClient_t, t, tnext, &svs.tcp_client_pool, entry ) { Z_Free( t ); } @@ -1957,6 +1949,9 @@ void SV_Shutdown( const char *finalmsg, killtype_t type ) { SV_FinalMessage( finalmsg, svc_disconnect ); } + // close server TCP socket + NET_Listen( qfalse ); + SV_MasterShutdown(); SV_ShutdownGameProgs(); diff --git a/source/sv_mvd.c b/source/sv_mvd.c index 4c2bc87..fffbd16 100644 --- a/source/sv_mvd.c +++ b/source/sv_mvd.c @@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. cvar_t *sv_mvd_enable; cvar_t *sv_mvd_auth; -cvar_t *sv_mvd_wait; +//cvar_t *sv_mvd_wait; cvar_t *sv_mvd_noblend; cvar_t *sv_mvd_nogun; cvar_t *sv_mvd_max_size; @@ -107,7 +107,7 @@ qboolean SV_MvdPlayerIsActive( edict_t *ent ) { } } - // they are likely following somene in case of PM_FREEZE + // they are likely following someone in case of PM_FREEZE if( ent->client->ps.pmove.pm_type == PM_FREEZE ) { return qfalse; } @@ -486,6 +486,7 @@ into the multicast buffer. ================== */ void SV_MvdBeginFrame( void ) { +#if 0 int i, j; int index; size_t length; @@ -550,6 +551,7 @@ void SV_MvdBeginFrame( void ) { } sv.mvd.paused = 0; +#endif } void SV_MvdEndFrame( void ) { @@ -1070,7 +1072,7 @@ static const cmdreg_t c_svmvd[] = { void SV_MvdRegister( void ) { sv_mvd_enable = Cvar_Get( "sv_mvd_enable", "0", CVAR_LATCH ); sv_mvd_auth = Cvar_Get( "sv_mvd_auth", "", CVAR_PRIVATE ); - sv_mvd_wait = Cvar_Get( "sv_mvd_wait", "0", CVAR_ROM ); // TODO + //sv_mvd_wait = Cvar_Get( "sv_mvd_wait", "0", CVAR_ROM ); // TODO sv_mvd_max_size = Cvar_Get( "sv_mvd_max_size", "0", 0 ); sv_mvd_max_duration = Cvar_Get( "sv_mvd_max_duration", "0", 0 ); sv_mvd_max_levels = Cvar_Get( "sv_mvd_max_levels", "1", 0 ); diff --git a/source/sv_public.h b/source/sv_public.h index 54e860a..c6c5e91 100644 --- a/source/sv_public.h +++ b/source/sv_public.h @@ -34,7 +34,8 @@ typedef enum { void SV_ProcessEvents( void ); void SV_Init (void); void SV_Shutdown( const char *finalmsg, killtype_t type ); -void SV_Frame (int msec); +void SV_Frame (unsigned msec); void SV_SetConsoleTitle( void ); +void SV_ConsoleOutput( const char *msg ); qboolean MVD_GetDemoPercent( int *percent, int *bufferPercent ); diff --git a/wiki/doc/server.mdwn b/wiki/doc/server.mdwn index 4d40950..b05ded4 100644 --- a/wiki/doc/server.mdwn +++ b/wiki/doc/server.mdwn @@ -57,6 +57,9 @@ with `sv_iplimit` variable. When set to address string, forces new clients to reconnect to this address as an additional proxy protection measure. This reconnection process is FAST. +- `set sv_show_name_changes 0` (boolean) +Broadcast player name changes to everyone. + - `set sv_uptime 0` (boolean) Display uptime in server info. @@ -65,8 +68,8 @@ MVD server ---------- - `set sv_http_enable 0` (boolean) -Enable HTTP connections, which are used for serving MVD clients and -status queries in HTML. +Enable HTTP connections used for serving MVD clients and answering +status queries in HTML format. - `set sv_http_maxclients 4` (integer) Maximum number of HTTP clients. Can be changed at any time, setting this to @@ -77,18 +80,26 @@ Maximum number of HTTP clients to be kept in the special pool of recently used slots for faster access and avoiding memory fragmentation. - `set sv_mvd_nogun 1` (boolean) +Reduce bandwidth usage by filtering on-screen gun updates out of MVD stream. - `set sv_mvd_noblend 0` (boolean) +Reduce bandwidth usage by filtering on-screen blend effects out of MVD stream. -- `set sv_mvd_max_duration 0` (boolean) +- `set sv_mvd_max_duration 0` (float) +Maximum duration in minutes of the locally recorded MVD. +Setting this to zero disables the limit. -- `set sv_mvd_max_size 0` (boolean) +- `set sv_mvd_max_size 0` (float) +Maximum size in KB of the locally recorded MVD. +Setting this to zero disables the limit. -- `set sv_mvd_wait 0` (boolean) +- `set sv_mvd_max_levels 1` (integer) +Maximum number of levels (map changes) locally recorded MVD may span. +Setting this to zero disables the limit. - `set sv_mvd_auth ""` (string) If not empty, perform Basic HTTP authentication of MVD connections. -Value should be in form of `user:pass`. +Value should have `user:pass` format. - `set sv_mvd_enable 0` (boolean) Enable recording local MVDs and serving MVD clients over HTTP. @@ -128,6 +139,9 @@ connection. This effectively specifies MVD stream delay seen by observers. Inuse percentage of the input buffer when MVD state machine transitions into running state to prevent buffer overrun. +- `set mvd_default_map "q2dm1"` (string) +Specifies default map used for the Waiting Room channel. + Hacks ---------- |