예제 #1
0
/*
* TV_Upstream_ParseServerData
*/
static void TV_Upstream_ParseServerData( upstream_t *upstream, msg_t *msg )
{
	int i, numpure;

	TV_Upstream_ClearState( upstream );

	upstream->state = CA_CONNECTED;

	// parse protocol version number
	i = MSG_ReadLong( msg );

	if( i != APP_PROTOCOL_VERSION )
		TV_Upstream_Error( upstream, "Server returned version %i, not %i", i, APP_PROTOCOL_VERSION );

	upstream->servercount = MSG_ReadLong( msg );
	upstream->snapFrameTime = (unsigned int) MSG_ReadShort( msg );

	Q_strncpyz( upstream->basegame, MSG_ReadString( msg ), sizeof( upstream->basegame ) );
	Q_strncpyz( upstream->game, MSG_ReadString( msg ), sizeof( upstream->game ) );

	// parse player entity number
	upstream->playernum = MSG_ReadShort( msg );

	// get the full level name
	Q_strncpyz( upstream->levelname, MSG_ReadString( msg ), sizeof( upstream->levelname ) );

	upstream->sv_bitflags = MSG_ReadByte( msg );
	upstream->reliable = ( ( upstream->sv_bitflags & SV_BITFLAGS_RELIABLE ) ? true : false );

	if( ( upstream->sv_bitflags & SV_BITFLAGS_HTTP ) != 0 ) {
		if( ( upstream->sv_bitflags & SV_BITFLAGS_HTTP_BASEURL ) != 0 ) {
			// read base upstream url
			MSG_ReadString( msg );
		}
		else {
			// http port number
			MSG_ReadShort( msg );
		}
	}
	
	// pure list

	// clean old, if necessary
	Com_FreePureList( &upstream->purelist );

	// add new
	numpure = MSG_ReadShort( msg );
	while( numpure > 0 )
	{
		const char *pakname = MSG_ReadString( msg );
		const unsigned checksum = MSG_ReadLong( msg );

		Com_AddPakToPureList( &upstream->purelist, pakname, checksum, upstream->mempool );

		numpure--;
	}

	TV_Upstream_AddReliableCommand( upstream, va( "configstrings %i 0", upstream->servercount ) );
}
예제 #2
0
/*
* TV_Upstream_ServerDisconnect_f
* 
* The server is changing levels
*/
static void TV_Upstream_ServerDisconnect_f( upstream_t *upstream )
{
	int type;

	type = atoi( Cmd_Argv( 1 ) );
	if( type < 0 || type >= DROP_TYPE_TOTAL )
		type = DROP_TYPE_GENERAL;

	TV_Upstream_Error( upstream, "Server disconnected: %s", Cmd_Argv( 2 ) );
}
예제 #3
0
/*
* TV_Upstream_Reject
*/
static void TV_Upstream_Reject_f( upstream_t *upstream, msg_t *msg ) {
	int rejecttype, rejectflag;
	char rejectmessage[MAX_STRING_CHARS];

	rejecttype = atoi( MSG_ReadStringLine( msg ) );
	if( rejecttype < 0 || rejecttype >= DROP_TYPE_TOTAL ) {
		rejecttype = DROP_TYPE_GENERAL;
	}

	rejectflag = atoi( MSG_ReadStringLine( msg ) );

	Q_strncpyz( rejectmessage, MSG_ReadStringLine( msg ), sizeof( rejectmessage ) );

	Com_Printf( "%s" S_COLOR_WHITE ": Upstream refused: %s\n", upstream->name, rejectmessage );
	if( rejectflag & DROP_FLAG_AUTORECONNECT ) {
		Com_Printf( "Automatic reconnecting allowed.\n" );
	} else {
		Com_Printf( "Automatic reconnecting not allowed.\n" );
	}

	TV_Upstream_Error( upstream, "Upstream refused: %s", rejectmessage );
}
예제 #4
0
/*
* TV_Upstream_ParseConfigstringCommand_f
*/
static void TV_Upstream_HandleConfigstring( upstream_t *upstream, int index, const char *val )
{
	char hostname[MAX_CONFIGSTRING_CHARS];
	msg_t msg;
	qbyte msgbuf[MAX_MSGLEN];

	if( !val || !val[0] )
		return;

	if( index < 0 || index >= MAX_CONFIGSTRINGS )
		TV_Upstream_Error( upstream, "configstring > MAX_CONFIGSTRINGS" );

	Q_strncpyz( upstream->configstrings[index], val, sizeof( upstream->configstrings[index] ) );

	if( index == CS_AUTORECORDSTATE )
	{
		// don't do a thing until we receive a "precache" command
		if( upstream->precacheDone )
			TV_Upstream_AutoRecordAction( upstream, upstream->configstrings[CS_AUTORECORDSTATE] );
		return;
	}

	if( index != CS_HOSTNAME )
		return;

	if( !upstream->demo.playing )
	{
		TV_Upstream_SetName( upstream, val );
		return;
	}

	// demos often come with generic hostnames, attempt to workaround that
	if( !Q_stricmp( val, APPLICATION " server" ) )
	{
		char *temp;
		size_t temp_size;
		const char *filebase;

		filebase = COM_FileBase( upstream->demo.filename );
		temp_size = strlen( filebase ) + strlen( APP_DEMO_EXTENSION_STR ) + 1;
		temp = Mem_TempMalloc( temp_size );
		Q_strncpyz( temp, filebase, temp_size );
		COM_ReplaceExtension( temp, APP_DEMO_EXTENSION_STR, temp_size );

		if( Com_GlobMatch( "*_auto[0-9][0-9][0-9][0-9]" APP_DEMO_EXTENSION_STR, temp, qfalse )
			|| Com_GlobMatch( "*_mvd" APP_DEMO_EXTENSION_STR, temp, qfalse ) )
			temp[strrchr( temp, '_' ) - temp] = '\0';
		else
			COM_StripExtension( temp );

		Q_strncpyz( hostname, va( S_COLOR_ORANGE "R: " S_COLOR_WHITE "%s", temp ), sizeof( hostname ) );

		Mem_TempFree( temp );
	}
	else
	{
		Q_strncpyz( hostname, va( S_COLOR_ORANGE "R: " S_COLOR_WHITE "%s", val ), sizeof( hostname ) );
	}

	TV_Upstream_SetName( upstream, hostname );

	// override CS_HOSTNAME in next packet
	MSG_Init( &msg, msgbuf, sizeof( msgbuf ) );
	MSG_WriteByte( &msg, svc_servercs );
	MSG_WriteString( &msg, va( "cs %i \"%s\"", CS_HOSTNAME, hostname ) );
	TV_Upstream_SavePacket( upstream, &msg, 0 );
}
예제 #5
0
/*
* TV_Upstream_ParseServerMessage
*/
void TV_Upstream_ParseServerMessage( upstream_t *upstream, msg_t *msg )
{
	int cmd;

	assert( upstream && upstream->state >= CA_HANDSHAKE );
	assert( msg );

	// parse the message
	while( upstream->state >= CA_HANDSHAKE )
	{
		if( msg->readcount > msg->cursize )
			TV_Upstream_Error( upstream, "Bad server message" );

		cmd = MSG_ReadByte( msg );

		if( cmd == -1 )
			break;

		// other commands
		switch( cmd )
		{
		default:
			TV_Upstream_Error( upstream, "Illegible server message" );

		case svc_nop:
			break;

		case svc_servercmd:
			if( !upstream->reliable )
			{
				int cmdNum = MSG_ReadLong( msg );
				if( cmdNum < 0 )
					TV_Upstream_Error( upstream, "Invalid cmdNum value" );
				if( cmdNum <= upstream->lastExecutedServerCommand )
				{
					MSG_ReadString( msg ); // read but ignore
					break;
				}
				upstream->lastExecutedServerCommand = cmdNum;
			}
			// fall trough
		case svc_servercs: // configstrings from demo files. they don't have acknowledge
			TV_Upstream_ParseServerCommand( upstream, msg );
			break;

		case svc_serverdata:
			if( upstream->state == CA_HANDSHAKE )
			{
				Cbuf_Execute(); // make sure any stuffed commands are done

				FS_Rescan();	// FIXME?

				TV_Upstream_ParseServerData( upstream, msg );
			}
			else
			{
				return; // ignore rest of the packet (serverdata is always sent alone)
			}
			break;

		case svc_spawnbaseline:
			TV_Upstream_ParseBaseline( upstream, msg );
			break;

		case svc_download:
			//CL_ParseDownload( msg );
			break;

		case svc_clcack:
			if( upstream->reliable )
				TV_Upstream_Error( upstream, "clack message while reliable" );
			upstream->reliableAcknowledge = (unsigned)MSG_ReadLong( msg );
			MSG_ReadLong( msg ); // ucmdAcknowledged
			break;

		case svc_frame:
			TV_Upstream_ParseFrame( upstream, msg );
			break;

		case svc_demoinfo:
			{
				int length;

				assert( upstream->demo.playing );

				length = MSG_ReadLong( msg );
				MSG_SkipData( msg, length );
			}
			break;

		case svc_playerinfo:
		case svc_packetentities:
		case svc_match:
			TV_Upstream_Error( upstream, "Out of place frame data" );
			break;

		case svc_extension:
			if( 1 )
			{
				int len;

				MSG_ReadByte( msg );			// extension id
				MSG_ReadByte( msg );			// version number
				len = MSG_ReadShort( msg );		// command length
				MSG_SkipData( msg, len );		// command data
			}
			break;
		}
	}

	// if recording demos, copy the message out
	if( upstream->demo.recording && !upstream->demo.waiting )
		TV_Upstream_WriteDemoMessage( upstream, msg );
}