diff options
author | Andrey Nazarov <skuller@skuller.net> | 2008-10-14 17:33:21 +0000 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2008-10-14 17:33:21 +0000 |
commit | 2ff447b2019b5696375fbc09d87416345418cd9a (patch) | |
tree | 615463d291db654810589e9c923e39546550c5b5 /source/sv_mvd.c | |
parent | 9b25ad2f9f46ea731f6834a96536859e8764ab28 (diff) |
Added `sv_mvd_bufsize', `sv_mvd_disconnect_time', `sv_mvd_suspend_time' cvars.
MVD dummy no longer attempts to reopen the scoreboard while suspended.
Extended maximum MVD/GTV client message size to 256 bytes.
Don't break message order client expects in parse_stream_start().
Support maxclients value change between MVD gamestates.
Added `mvd_suspend_time', `mvd_username', `mvd_password' cvars.
Fixed MVD client retry backoff time.
Diffstat (limited to 'source/sv_mvd.c')
-rw-r--r-- | source/sv_mvd.c | 215 |
1 files changed, 123 insertions, 92 deletions
diff --git a/source/sv_mvd.c b/source/sv_mvd.c index 03aabbe..0bf663e 100644 --- a/source/sv_mvd.c +++ b/source/sv_mvd.c @@ -46,8 +46,8 @@ typedef struct { unsigned maxbuf; unsigned bufcount; - byte buffer[256]; - byte *data; + byte buffer[MAX_GTC_MSGLEN+4]; // recv buffer + byte *data; // send buffer char name[MAX_CLIENT_NAME]; char version[MAX_QPATH]; @@ -89,6 +89,7 @@ static LIST_DECL( gtv_host_list ); static cvar_t *sv_mvd_enable; static cvar_t *sv_mvd_maxclients; +static cvar_t *sv_mvd_bufsize; static cvar_t *sv_mvd_auth; static cvar_t *sv_mvd_noblend; static cvar_t *sv_mvd_nogun; @@ -100,6 +101,8 @@ static cvar_t *sv_mvd_begincmd; static cvar_t *sv_mvd_scorecmd; static cvar_t *sv_mvd_autorecord; static cvar_t *sv_mvd_capture_flags; +static cvar_t *sv_mvd_disconnect_time; +static cvar_t *sv_mvd_suspend_time; static qboolean mvd_enable( void ); static void mvd_disable( void ); @@ -393,7 +396,7 @@ static void dummy_run( void ) { // check if the layout is constantly updated. if not, // game mod has probably closed the scoreboard, open it again - if( sv_mvd_scorecmd->string[0] ) { + if( mvd.active && sv_mvd_scorecmd->string[0] ) { if( svs.realtime - mvd.layout_time > 9000 ) { Cbuf_AddTextEx( &dummy_buffer, sv_mvd_scorecmd->string ); mvd.layout_time = svs.realtime; @@ -761,8 +764,62 @@ static void emit_frame( void ) { MSG_WriteShort( 0 ); // end of packetentities } -#define MVD_CLIENTS_TIMEOUT (15*60*1000) -#define MVD_PLAYERS_TIMEOUT (5*60*1000) +static void suspend_streams( void ) { + gtv_client_t *client; + + FOR_EACH_ACTIVE_GTV( client ) { + // send stream suspend marker + write_message( client, GTS_STREAM_DATA ); +#if USE_ZLIB + flush_stream( client, Z_SYNC_FLUSH ); +#endif + } + Com_DPrintf( "Suspending MVD streams.\n" ); + mvd.active = qfalse; +} + +static void resume_streams( void ) { + gtv_client_t *client; + + // build and emit gamestate + build_gamestate(); + emit_gamestate(); + + FOR_EACH_ACTIVE_GTV( client ) { + // send gamestate + write_message( client, GTS_STREAM_DATA ); +#if USE_ZLIB + flush_stream( client, Z_SYNC_FLUSH ); +#endif + } + + // write it to demofile + if( mvd.recording ) { + rec_write(); + } + + // clear gamestate + SZ_Clear( &msg_write ); + + SZ_Clear( &mvd.datagram ); + SZ_Clear( &mvd.message ); + + Com_DPrintf( "Resuming MVD streams.\n" ); + mvd.active = qtrue; +} + +static qboolean players_active( void ) { + int i; + edict_t *ent; + + for( i = 0; i < sv_maxclients->integer; i++ ) { + ent = EDICT_NUM( i + 1 ); + if( ent != mvd.dummy->edict && player_is_active( ent ) ) { + return qtrue; + } + } + return qfalse; +} /* ================== @@ -770,75 +827,37 @@ SV_MvdBeginFrame ================== */ void SV_MvdBeginFrame( void ) { - gtv_client_t *client; - int i; + unsigned delta; // do nothing if not enabled if( !mvd.dummy ) { return; } - // disconnect MVD dummy if no MVD clients are active for 15 minutes - if( !sv_mvd_autorecord->integer ) { - // FIXME: should not really count unauthenticated/zombie clients, etc - if( mvd.recording || !LIST_EMPTY( >v_client_list ) ) { - mvd.clients_active = svs.realtime; - } else if( svs.realtime - mvd.clients_active > MVD_CLIENTS_TIMEOUT ) { - Com_DPrintf( "Disconnecting dummy MVD client.\n" ); - SV_DropClient( mvd.dummy, NULL ); - return; - } - } + delta = sv_mvd_disconnect_time->value * 60 * 1000; - // suspend all MVD streams if no players are active for 5 minutes - for( i = 0; i < sv_maxclients->integer; i++ ) { - edict_t * ent = EDICT_NUM( i + 1 ); - if( ent != mvd.dummy->edict && player_is_active( ent ) ) { - mvd.players_active = svs.realtime; - break; - } + // disconnect MVD dummy if no MVD clients are active for some time + // FIXME: should not really count unauthenticated/zombie clients + if( !delta || mvd.recording || !LIST_EMPTY( >v_client_list ) ) { + mvd.clients_active = svs.realtime; + } else if( svs.realtime - mvd.clients_active > delta ) { + Com_DPrintf( "Disconnecting dummy MVD client.\n" ); + SV_DropClient( mvd.dummy, NULL ); + return; } - if( i == sv_maxclients->integer ) { - if( mvd.active ) { - if( svs.realtime - mvd.players_active > MVD_PLAYERS_TIMEOUT ) { - FOR_EACH_ACTIVE_GTV( client ) { - // send stream suspend marker - write_message( client, GTS_STREAM_DATA ); -#if USE_ZLIB - flush_stream( client, Z_SYNC_FLUSH ); -#endif - } - Com_DPrintf( "Suspending MVD streams.\n" ); - mvd.active = qfalse; - } - } - } else if( !mvd.active ) { - // build and emit gamestate - build_gamestate(); - emit_gamestate(); + delta = sv_mvd_suspend_time->value * 60 * 1000; - FOR_EACH_ACTIVE_GTV( client ) { - // send gamestate - write_message( client, GTS_STREAM_DATA ); -#if USE_ZLIB - flush_stream( client, Z_SYNC_FLUSH ); -#endif + // suspend/resume MVD streams depending on players activity + if( !delta || players_active() ) { + mvd.players_active = svs.realtime; + if( !mvd.active ) { + resume_streams(); } - - // write it to demofile - if( mvd.recording ) { - rec_write(); + } else if( mvd.active ) { + if( svs.realtime - mvd.players_active > delta ) { + suspend_streams(); } - - // clear gamestate - SZ_Clear( &msg_write ); - - SZ_Clear( &mvd.datagram ); - SZ_Clear( &mvd.message ); - - Com_DPrintf( "Resuming MVD streams.\n" ); - mvd.active = qtrue; } } @@ -1151,6 +1170,9 @@ static void flush_stream( gtv_client_t *client, int flush ) { size_t len; int ret; + if( client->state <= cs_zombie ) { + return; + } if( !z->state ) { return; } @@ -1246,7 +1268,7 @@ static void write_stream( gtv_client_t *client, void *data, size_t len ) { } else #endif - if( !FIFO_TryWrite( fifo, data, len ) ) { + if( FIFO_Write( fifo, data, len ) != len ) { drop_client( client, "overflowed" ); } } @@ -1265,18 +1287,24 @@ static void write_message( gtv_client_t *client, gtv_serverop_t op ) { static void parse_hello( gtv_client_t *client ) { int protocol, flags; + size_t size; byte *data; if( client->state >= cs_primed ) { - write_message( client, GTS_BADREQUEST ); drop_client( client, "duplicated hello message" ); return; } + // client should have already consumed the magic + if( FIFO_Usage( &client->stream.send ) ) { + drop_client( client, "send buffer not empty" ); + return; + } + protocol = MSG_ReadWord(); if( protocol != GTV_PROTOCOL_VERSION ) { write_message( client, GTS_BADREQUEST ); - drop_client( client, "bad protocol" ); + drop_client( client, "bad protocol version" ); return; } @@ -1292,11 +1320,17 @@ static void parse_hello( gtv_client_t *client ) { return; } - data = SV_Malloc( MAX_MSGLEN * 2 ); +#if !USE_ZLIB + flags &= ~GTF_DEFLATE; +#endif - // TODO: expand recv buffer + Cvar_ClampInteger( sv_mvd_bufsize, 1, 4 ); + + // allocate larger send buffer + size = MAX_GTS_MSGLEN * sv_mvd_bufsize->integer; + data = SV_Malloc( size ); client->stream.send.data = data; - client->stream.send.size = MAX_MSGLEN * 2; + client->stream.send.size = size; client->data = data; client->flags = flags; client->state = cs_primed; @@ -1318,8 +1352,6 @@ static void parse_hello( gtv_client_t *client ) { } #endif - mvd.clients_active = svs.realtime; - Com_Printf( "Accepted MVD client %s[%s]\n", client->name, NET_AdrToString( &client->stream.address ) ); } @@ -1339,7 +1371,14 @@ static void parse_ping( gtv_client_t *client ) { static void parse_stream_start( gtv_client_t *client ) { int maxbuf; - if( client->state < cs_primed ) { + if( client->state != cs_primed ) { + drop_client( client, "unexpected stream start message" ); + return; + } + + if( !mvd_enable() ) { + write_message( client, GTS_ERROR ); + drop_client( client, "couldn't create MVD dummy" ); return; } @@ -1353,12 +1392,6 @@ static void parse_stream_start( gtv_client_t *client ) { List_Append( >v_active_list, &client->active ); - if( !mvd_enable() ) { - write_message( client, GTS_ERROR ); - drop_client( client, "couldn't create MVD dummy" ); - return; - } - // send ack to client write_message( client, GTS_STREAM_START ); @@ -1378,7 +1411,8 @@ static void parse_stream_start( gtv_client_t *client ) { } static void parse_stream_stop( gtv_client_t *client ) { - if( client->state < cs_spawned ) { + if( client->state != cs_spawned ) { + drop_client( client, "unexpected stream stop message" ); return; } @@ -1415,6 +1449,7 @@ static qboolean parse_message( gtv_client_t *client ) { // send it back write_stream( client, &magic, 4 ); + return qfalse; } // parse msglen @@ -1427,7 +1462,7 @@ static qboolean parse_message( gtv_client_t *client ) { drop_client( client, "end of stream" ); return qfalse; } - if( msglen > 128 ) { + if( msglen > MAX_GTC_MSGLEN ) { drop_client( client, "oversize message" ); return qfalse; } @@ -1516,9 +1551,9 @@ static void accept_client( netstream_t *stream ) { s = &client->stream; s->recv.data = client->buffer; - s->recv.size = 128; - s->send.data = client->buffer + 128; - s->send.size = 128; + s->recv.size = MAX_GTC_MSGLEN; + s->send.data = client->buffer + MAX_GTC_MSGLEN; + s->send.size = 4; // need no more than that initially s->socket = stream->socket; s->address = stream->address; s->state = stream->state; @@ -1690,10 +1725,6 @@ static void mvd_drop( gtv_serverop_t op ) { FOR_EACH_GTV( client ) { switch( client->state ) { case cs_spawned: - if( mvd.active ) { - write_message( client, GTS_STREAM_STOP ); - } - // fall through case cs_primed: write_message( client, op ); drop_client( client, NULL ); @@ -1718,13 +1749,9 @@ static qboolean mvd_enable( void ) { return qfalse; } dummy_spawn(); -#if 0 - build_gamestate(); - mvd.clients_active = mvd.players_active = svs.realtime; - mvd.active = qtrue; -#else + + // check for activation SV_MvdBeginFrame(); -#endif } return qtrue; } @@ -1762,6 +1789,7 @@ void SV_MvdMapChanged( void ) { return; } Com_Printf( "Spawning MVD dummy for auto-recording\n" ); + Cvar_Set( "sv_mvd_suspend_time", "0" ); } dummy_spawn(); @@ -2092,6 +2120,7 @@ static const cmdreg_t c_svmvd[] = { void SV_MvdRegister( void ) { sv_mvd_enable = Cvar_Get( "sv_mvd_enable", "0", CVAR_LATCH ); sv_mvd_maxclients = Cvar_Get( "sv_mvd_maxclients", "8", CVAR_LATCH ); + sv_mvd_bufsize = Cvar_Get( "sv_mvd_bufsize", "2", CVAR_LATCH ); sv_mvd_auth = Cvar_Get( "sv_mvd_auth", "", CVAR_PRIVATE ); sv_mvd_maxsize = Cvar_Get( "sv_mvd_maxsize", "0", 0 ); sv_mvd_maxtime = Cvar_Get( "sv_mvd_maxtime", "0", 0 ); @@ -2105,6 +2134,8 @@ void SV_MvdRegister( void ) { "putaway; wait 10; help;", 0 ); sv_mvd_autorecord = Cvar_Get( "sv_mvd_autorecord", "0", CVAR_LATCH ); sv_mvd_capture_flags = Cvar_Get( "sv_mvd_capture_flags", "5", 0 ); + sv_mvd_disconnect_time = Cvar_Get( "sv_mvd_disconnect_time", "15", 0 ); + sv_mvd_suspend_time = Cvar_Get( "sv_mvd_suspend_time", "5", 0 ); dummy_buffer.text = dummy_buffer_text; dummy_buffer.maxsize = sizeof( dummy_buffer_text ); |