summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2008-08-28 17:35:47 +0000
committerAndrey Nazarov <skuller@skuller.net>2008-08-28 17:35:47 +0000
commit8d466c8c99a82c9fa87d2c8a932413da1ac89e04 (patch)
tree9954623456ae4dc245daa98f57f913f9892a742b
parent651dbdd53d61b75108ffdc95f3efdb285adc7170 (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.c2
-rw-r--r--source/cl_main.c6
-rw-r--r--source/cl_public.h2
-rw-r--r--source/common.c3
-rw-r--r--source/mvd_game.c16
-rw-r--r--source/net_common.c49
-rw-r--r--source/sv_http.c74
-rw-r--r--source/sv_local.h6
-rw-r--r--source/sv_main.c45
-rw-r--r--source/sv_mvd.c8
-rw-r--r--source/sv_public.h3
-rw-r--r--wiki/doc/server.mdwn26
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
----------