示例#1
0
/*
* TV_Downstream_SendClientsFragments
*/
qboolean TV_Downstream_SendClientsFragments( void )
{
	client_t *client;
	int i;
	qboolean remaining = qfalse;

	// send a message to each connected client
	for( i = 0, client = tvs.clients; i < tv_maxclients->integer; i++, client++ )
	{
		if( client->state == CS_FREE || client->state == CS_ZOMBIE )
			continue;

		if( !client->netchan.unsentFragments )
			continue;

		if( !Netchan_TransmitNextFragment( &client->netchan ) )
		{
			Com_Printf( "%s" S_COLOR_WHITE ": Error sending fragment: %s\n", client->name, NET_ErrorString() );
			if( client->reliable )
			{
				TV_Downstream_DropClient( client, DROP_TYPE_GENERAL, "Error sending fragment: %s\n",
					NET_ErrorString() );
			}
			continue;
		}

		if( client->netchan.unsentFragments )
			remaining = qtrue;
	}

	return remaining;
}
示例#2
0
/*
=================
SV_Netchan_TransmitNextFragment
=================
*/
void SV_Netchan_TransmitNextFragment(client_t *client)
{
	Netchan_TransmitNextFragment(&client->netchan);
	while (!client->netchan.unsentFragments && client->netchan_start_queue)
	{
		// make sure the netchan queue has been properly initialized (you never know)
		//if (!client->netchan_end_queue) {
		//  Com_Error(ERR_DROP, "netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment");
		//}
		// the last fragment was transmitted, check wether we have queued messages
		netchan_buffer_t *netbuf = client->netchan_start_queue;

		// pop from queue
		client->netchan_start_queue = netbuf->next;
		if (!client->netchan_start_queue)
		{
			client->netchan_end_queue = NULL;
		}

		SV_Netchan_Encode(client, &netbuf->msg, netbuf->lastClientCommandString);

		Netchan_Transmit(&client->netchan, netbuf->msg.cursize, netbuf->msg.data);

		Z_Free(netbuf);
	}
}
/*
=================
SV_Netchan_TransmitNextFragment
=================
*/
void SV_Netchan_TransmitNextFragment( client_t *client ) {
	Netchan_TransmitNextFragment( &client->netchan );
	if (!client->netchan.unsentFragments)
	{
		// make sure the netchan queue has been properly initialized (you never know)
		if (!client->netchan_end_queue) {
			Com_Error(ERR_DROP, "netchan queue is not properly initialized in SV_Netchan_TransmitNextFragment\n");
		}
		// the last fragment was transmitted, check wether we have queued messages
		if (client->netchan_start_queue) {
			netchan_buffer_t *netbuf;
			Com_DPrintf("#462 Netchan_TransmitNextFragment: popping a queued message for transmit\n");
			netbuf = client->netchan_start_queue;
			SV_Netchan_Encode( client, &netbuf->msg );
			Netchan_Transmit( &client->netchan, netbuf->msg.cursize, netbuf->msg.data );
			// pop from queue
			client->netchan_start_queue = netbuf->next;
			if (!client->netchan_start_queue) {
				Com_DPrintf("#462 Netchan_TransmitNextFragment: emptied queue\n");
				client->netchan_end_queue = &client->netchan_start_queue;
			}
			else
				Com_DPrintf("#462 Netchan_TransmitNextFragment: remaining queued message\n");
			Z_Free(netbuf);
		} 
	}	
}
示例#4
0
文件: net_chan.c 项目: tenght/qfusion
/*
* Netchan_Transmit
* 
* Sends a message to a connection, fragmenting if necessary
* A 0 length will still generate a packet.
*/
bool Netchan_Transmit( netchan_t *chan, msg_t *msg )
{
	msg_t send;
	uint8_t send_buf[MAX_PACKETLEN];

	assert( msg );

	if( msg->cursize > MAX_MSGLEN )
	{
		Com_Error( ERR_DROP, "Netchan_Transmit: Excessive length = %i", msg->cursize );
		return false;
	}
	chan->unsentFragmentStart = 0;
	chan->unsentIsCompressed = false;

	// fragment large reliable messages
	if( msg->cursize >= FRAGMENT_SIZE )
	{
		chan->unsentFragments = true;
		chan->unsentLength = msg->cursize;
		chan->unsentIsCompressed = msg->compressed;
		memcpy( chan->unsentBuffer, msg->data, msg->cursize );

		// only send the first fragment now
		return Netchan_TransmitNextFragment( chan );
	}

	// write the packet header
	MSG_Init( &send, send_buf, sizeof( send_buf ) );
	MSG_Clear( &send );

	MSG_WriteLong( &send, chan->outgoingSequence );
	// wsw : jal : by now our header sends incoming ack too (q3 doesn't)
	// wsw : jal : also add compressed information if it's compressed
	if( msg->compressed )
		MSG_WriteLong( &send, chan->incomingSequence | FRAGMENT_BIT );
	else
		MSG_WriteLong( &send, chan->incomingSequence );

	chan->outgoingSequence++;

	// send the game port if we are a client
	if( !chan->socket->server )
		MSG_WriteShort( &send, game_port );

	MSG_CopyData( &send, msg->data, msg->cursize );

	// send the datagram
	if( !NET_SendPacket( chan->socket, send.data, send.cursize, &chan->remoteAddress ) )
		return false;

	if( showpackets->integer )
	{
		Com_Printf( "%s send %4i : s=%i ack=%i\n", NET_SocketToString( chan->socket ), send.cursize,
			chan->outgoingSequence - 1, chan->incomingSequence );
	}

	return true;
}
示例#5
0
/*
===============
Netchan_Transmit

Sends a message to a connection, fragmenting if necessary
A 0 length will still generate a packet.
================
*/
void Netchan_Transmit( netchan_t* chan, int length, const byte* data )
{
	msg_s       send;
	byte        send_buf[MAX_PACKETLEN];
	
	if ( length > MAX_MSGLEN )
	{
		Com_Error( ERR_DROP, "Netchan_Transmit: length = %i", length );
	}
	chan->unsentFragmentStart = 0;
	
	// fragment large reliable messages
	if ( length >= FRAGMENT_SIZE )
	{
		chan->unsentFragments = true;
		chan->unsentLength = length;
		memcpy( chan->unsentBuffer, data, length );
		
		// only send the first fragment now
		Netchan_TransmitNextFragment( chan );
		
		return;
	}
	
	// write the packet header
	MSG_InitOOB( &send, send_buf, sizeof( send_buf ) );
	
	MSG_WriteLong( &send, chan->outgoingSequence );
	
	// send the qport if we are a client
	if ( chan->sock == NS_CLIENT )
		MSG_WriteShort( &send, qport->integer );
		
#ifdef LEGACY_PROTOCOL
	if ( !chan->compat )
#endif
		MSG_WriteLong( &send, NETCHAN_GENCHECKSUM( chan->challenge, chan->outgoingSequence ) );
		
	chan->outgoingSequence++;
	
	MSG_WriteData( &send, data, length );
	
	// send the datagram
	NET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress );
	
	// Store send time and size of this packet for rate control
	chan->lastSentTime = Sys_Milliseconds();
	chan->lastSentSize = send.cursize;
	
	if ( showpackets->integer )
	{
		Com_Printf( "%s send %4i : s=%i ack=%i\n"
					, netsrcString[ chan->sock ]
					, send.cursize
					, chan->outgoingSequence - 1
					, chan->incomingSequence );
	}
}
示例#6
0
/*
=======================================================================================================================================
CL_Netchan_TransmitNextFragment
=======================================================================================================================================
*/
qboolean CL_Netchan_TransmitNextFragment(netchan_t *chan) {

	if (chan->unsentFragments) {
		Netchan_TransmitNextFragment(chan);
		return qtrue;
	}

	return qfalse;
}
示例#7
0
文件: net_chan.c 项目: tenght/qfusion
/*
* Netchan_PushAllFragments
* 
* Send all remaining fragments at once
*/
bool Netchan_PushAllFragments( netchan_t *chan )
{
	while( chan->unsentFragments )
	{
		if( !Netchan_TransmitNextFragment( chan ) )
			return false;
	}

	return true;
}
示例#8
0
/*
=======================================================================================================================================
SV_Netchan_TransmitNextFragment
=======================================================================================================================================
*/
int SV_Netchan_TransmitNextFragment(client_t *client) {

	if (client->netchan.unsentFragments) {
		Netchan_TransmitNextFragment(&client->netchan);
		return SV_RateMsec(client);
	} else if (client->netchan_start_queue) {
		SV_Netchan_TransmitNextInQueue(client);
		return SV_RateMsec(client);
	}

	return -1;
}
示例#9
0
/*
===============
Netchan_Transmit

Sends a message to a connection, fragmenting if necessary
A 0 length will still generate a packet.
================
*/
void Netchan_Transmit( netchan_t *chan, int length, const byte *data )
{
	msg_t send;
	byte  send_buf[ MAX_PACKETLEN ];

	if ( length > MAX_MSGLEN )
	{
		Com_Error( ERR_DROP, "Netchan_Transmit: length = %i", length );
	}

	chan->unsentFragmentStart = 0;

	// fragment large reliable messages
	if ( length >= FRAGMENT_SIZE )
	{
		chan->unsentFragments = qtrue;
		chan->unsentLength = length;
		Com_Memcpy( chan->unsentBuffer, data, length );

		// only send the first fragment now
		Netchan_TransmitNextFragment( chan );

		return;
	}

	// write the packet header
	MSG_InitOOB( &send, send_buf, sizeof( send_buf ) );

	MSG_WriteLong( &send, chan->outgoingSequence );
	chan->outgoingSequence++;

	// send the qport if we are a client
	if ( chan->sock == NS_CLIENT )
	{
		MSG_WriteShort( &send, qport->integer );
	}

	MSG_WriteData( &send, data, length );

	// send the datagram
	NET_SendPacket( chan->sock, send.cursize, send.data, chan->remoteAddress );

	if ( showpackets->integer )
	{
		Com_Printf( "%s send %4i : s=%i ack=%i\n"
		            , netsrcString[ chan->sock ]
		            , send.cursize
		            , chan->outgoingSequence - 1
		            , chan->incomingSequence );
	}
}
示例#10
0
/*
===============
SV_Netchan_Transmit

TTimo
show_bug.cgi?id=462
if there are some unsent fragments (which may happen if the snapshots
and the gamestate are fragmenting, and collide on send for instance)
then buffer them and make sure they get sent in correct order
================
*/
void SV_Netchan_Transmit( client_t *client, msg_t *msg )
{
	//int length, const byte *data ) {
	MSG_WriteByte( msg, svc_EOF );
	SV_WriteBinaryMessage( msg, client );

	if ( client->netchan.unsentFragments )
	{
		netchan_buffer_t *netbuf;

		//Com_DPrintf("SV_Netchan_Transmit: there are unsent fragments remaining\n");
		netbuf = ( netchan_buffer_t * ) Z_Malloc( sizeof( netchan_buffer_t ) );

		// store the msg, we can't store it encoded, as the encoding depends on stuff we still have to finish sending
		MSG_Copy( &netbuf->msg, netbuf->msgBuffer, sizeof( netbuf->msgBuffer ), msg );

		// copy the command, since the command number used for encryption is
		// already compressed in the buffer, and receiving a new command would
		// otherwise lose the proper encryption key
		strcpy( netbuf->lastClientCommandString, client->lastClientCommandString );

		// insert it in the queue, the message will be encoded and sent later
		//% *client->netchan_end_queue = netbuf;
		//% client->netchan_end_queue = &(*client->netchan_end_queue)->next;
		netbuf->next = NULL;

		if ( !client->netchan_start_queue )
		{
			client->netchan_start_queue = netbuf;
		}
		else
		{
			client->netchan_end_queue->next = netbuf;
		}

		client->netchan_end_queue = netbuf;

		// emit the next fragment of the current message for now
		Netchan_TransmitNextFragment( &client->netchan );
	}
	else
	{
		SV_Netchan_Encode( client, msg, client->lastClientCommandString );
		Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
	}
}
示例#11
0
/*
===============
SV_Netchan_Transmit

TTimo
show_bug.cgi?id=462
if there are some unsent fragments (which may happen if the snapshots
and the gamestate are fragmenting, and collide on send for instance)
then buffer them and make sure they get sent in correct order
================
*/
void SV_Netchan_Transmit( client_t *client, msg_t *msg ) {   //int length, const byte *data ) {
	MSG_WriteByte( msg, svc_EOF );
	if ( client->netchan.unsentFragments ) {
		netchan_buffer_t *netbuf;
		//Com_DPrintf("SV_Netchan_Transmit: there are unsent fragments remaining\n");
		netbuf = (netchan_buffer_t *)Z_Malloc( sizeof( netchan_buffer_t ) );
		// store the msg, we can't store it encoded, as the encoding depends on stuff we still have to finish sending
		MSG_Copy( &netbuf->msg, netbuf->msgBuffer, sizeof( netbuf->msgBuffer ), msg );
		netbuf->next = NULL;
		// insert it in the queue, the message will be encoded and sent later
		*client->netchan_end_queue = netbuf;
		client->netchan_end_queue = &( *client->netchan_end_queue )->next;
		// emit the next fragment of the current message for now
		Netchan_TransmitNextFragment( &client->netchan );
	} else {
		SV_Netchan_Encode( client, msg );
		Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
	}
}
示例#12
0
/*
===============
SV_Netchan_Transmit

TTimo
show_bug.cgi?id=462
if there are some unsent fragments (which may happen if the snapshots
and the gamestate are fragmenting, and collide on send for instance)
then buffer them and make sure they get sent in correct order
================
*/
void SV_Netchan_Transmit( client_t *client, msg_t *msg )
{
    //int length, const byte *data ) {
    MSG_WriteByte( msg, svc_EOF );
    SV_WriteBinaryMessage( msg, client );

    if ( client->netchan.unsentFragments )
    {
        netchan_buffer_t *netbuf;

        //Log::Debug("SV_Netchan_Transmit: there are unsent fragments remaining");
        netbuf = ( netchan_buffer_t * ) Z_Malloc( sizeof( netchan_buffer_t ) );

        MSG_Copy( &netbuf->msg, netbuf->msgBuffer, sizeof( netbuf->msgBuffer ), msg );

        // copy the command, since the command number used for encryption is
        // already compressed in the buffer, and receiving a new command would
        // otherwise lose the proper encryption key
        strcpy( netbuf->lastClientCommandString, client->lastClientCommandString );

        netbuf->next = nullptr;

        if ( !client->netchan_start_queue )
        {
            client->netchan_start_queue = netbuf;
        }
        else
        {
            client->netchan_end_queue->next = netbuf;
        }

        client->netchan_end_queue = netbuf;

        // emit the next fragment of the current message for now
        Netchan_TransmitNextFragment( &client->netchan );
    }
    else
    {
        Netchan_Transmit( &client->netchan, msg->cursize, msg->data );
    }
}
示例#13
0
/*
=================
SV_Netchan_TransmitNextFragment
=================
*/
void SV_Netchan_TransmitNextFragment( netchan_t *chan ) {
	Netchan_TransmitNextFragment( chan );
}
示例#14
0
/*
===================
CL_WritePacket

Create and send the command packet to the server
Including both the reliable commands and the usercmds

A client packet will contain something like:

4 sequence number
2 qport
4 serverid
4 acknowledged sequence number
4 clc.serverCommandSequence
<optional reliable commands>
1 clc_move or clc_moveNoDelta
1 command count
<count * usercmds>

===================
*/
void CL_WritePacket()
{
	msg_t     buf;
	byte      data[ MAX_MSGLEN ];
	int       i, j;
	usercmd_t *cmd, *oldcmd;
	usercmd_t nullcmd;
	int       packetNum;
	int       oldPacketNum;
	int       count;

	// don't send anything if playing back a demo
	if ( clc.demoplaying || cls.state == CA_CINEMATIC )
	{
		return;
	}

	memset( &nullcmd, 0, sizeof( nullcmd ) );
	oldcmd = &nullcmd;

	MSG_Init( &buf, data, sizeof( data ) );

	MSG_Bitstream( &buf );
	// write the current serverId so the server
	// can tell if this is from the current gameState
	MSG_WriteLong( &buf, cl.serverId );

	// write the last message we received, which can
	// be used for delta compression, and is also used
	// to tell if we dropped a gamestate
	MSG_WriteLong( &buf, clc.serverMessageSequence );

	// write the last reliable message we received
	MSG_WriteLong( &buf, clc.serverCommandSequence );

	// write any unacknowledged clientCommands
	// NOTE TTimo: if you verbose this, you will see that there are quite a few duplicates
	// typically several unacknowledged cp or userinfo commands stacked up
	for ( i = clc.reliableAcknowledge + 1; i <= clc.reliableSequence; i++ )
	{
		MSG_WriteByte( &buf, clc_clientCommand );
		MSG_WriteLong( &buf, i );
		MSG_WriteString( &buf, clc.reliableCommands[ i & ( MAX_RELIABLE_COMMANDS - 1 ) ] );
	}

	// we want to send all the usercmds that were generated in the last
	// few packet, so even if a couple packets are dropped in a row,
	// all the cmds will make it to the server
	if ( cl_packetdup->integer < 0 )
	{
		Cvar_Set( "cl_packetdup", "0" );
	}
	else if ( cl_packetdup->integer > 5 )
	{
		Cvar_Set( "cl_packetdup", "5" );
	}

	oldPacketNum = ( clc.netchan.outgoingSequence - 1 - cl_packetdup->integer ) & PACKET_MASK;
	count = cl.cmdNumber - cl.outPackets[ oldPacketNum ].p_cmdNumber;

	if ( count > MAX_PACKET_USERCMDS )
	{
		count = MAX_PACKET_USERCMDS;
		Com_Printf( "MAX_PACKET_USERCMDS" );
	}

#ifdef USE_VOIP

	if ( clc.voipOutgoingDataSize > 0 )
	{
		if ( ( clc.voipFlags & VOIP_SPATIAL ) || Com_IsVoipTarget( clc.voipTargets, sizeof( clc.voipTargets ), -1 ) )
		{
			MSG_WriteByte( &buf, clc_voip );
			MSG_WriteByte( &buf, clc.voipOutgoingGeneration );
			MSG_WriteLong( &buf, clc.voipOutgoingSequence );
			MSG_WriteByte( &buf, clc.voipOutgoingDataFrames );
			MSG_WriteData( &buf, clc.voipTargets, sizeof( clc.voipTargets ) );
			MSG_WriteByte( &buf, clc.voipFlags );
			MSG_WriteShort( &buf, clc.voipOutgoingDataSize );
			MSG_WriteData( &buf, clc.voipOutgoingData, clc.voipOutgoingDataSize );

			// If we're recording a demo, we have to fake a server packet with
			//  this VoIP data so it gets to disk; the server doesn't send it
			//  back to us, and we might as well eliminate concerns about dropped
			//  and misordered packets here.
			if ( clc.demorecording && !clc.demowaiting )
			{
				const int voipSize = clc.voipOutgoingDataSize;
				msg_t     fakemsg;
				byte      fakedata[ MAX_MSGLEN ];
				MSG_Init( &fakemsg, fakedata, sizeof( fakedata ) );
				MSG_Bitstream( &fakemsg );
				MSG_WriteLong( &fakemsg, clc.reliableAcknowledge );
				MSG_WriteByte( &fakemsg, svc_voip );
				MSG_WriteShort( &fakemsg, clc.clientNum );
				MSG_WriteByte( &fakemsg, clc.voipOutgoingGeneration );
				MSG_WriteLong( &fakemsg, clc.voipOutgoingSequence );
				MSG_WriteByte( &fakemsg, clc.voipOutgoingDataFrames );
				MSG_WriteShort( &fakemsg, clc.voipOutgoingDataSize );
				MSG_WriteBits( &fakemsg, clc.voipFlags, VOIP_FLAGCNT );
				MSG_WriteData( &fakemsg, clc.voipOutgoingData, voipSize );
				MSG_WriteByte( &fakemsg, svc_EOF );
				CL_WriteDemoMessage( &fakemsg, 0 );
			}

			clc.voipOutgoingSequence += clc.voipOutgoingDataFrames;
			clc.voipOutgoingDataSize = 0;
			clc.voipOutgoingDataFrames = 0;
		}
		else
		{
			// We have data, but no targets. Silently discard all data
			clc.voipOutgoingDataSize = 0;
			clc.voipOutgoingDataFrames = 0;
		}
	}

#endif

	if ( count >= 1 )
	{
		if ( cl_showSend->integer )
		{
			Com_Printf( "(%i)", count );
		}

		// begin a client move command
		if ( cl_nodelta->integer || !cl.snap.valid || clc.demowaiting || clc.serverMessageSequence != cl.snap.messageNum )
		{
			MSG_WriteByte( &buf, clc_moveNoDelta );
		}
		else
		{
			MSG_WriteByte( &buf, clc_move );
		}

		// write the command count
		MSG_WriteByte( &buf, count );

		// write all the commands, including the predicted command
		for ( i = 0; i < count; i++ )
		{
			j = ( cl.cmdNumber - count + i + 1 ) & CMD_MASK;
			cmd = &cl.cmds[ j ];
			MSG_WriteDeltaUsercmd( &buf, oldcmd, cmd );
			oldcmd = cmd;
		}
	}

	//
	// deliver the message
	//
	packetNum = clc.netchan.outgoingSequence & PACKET_MASK;
	cl.outPackets[ packetNum ].p_realtime = cls.realtime;
	cl.outPackets[ packetNum ].p_serverTime = oldcmd->serverTime;
	cl.outPackets[ packetNum ].p_cmdNumber = cl.cmdNumber;
	clc.lastPacketSentTime = cls.realtime;

	if ( cl_showSend->integer )
	{
		Com_Printf("%i ", buf.cursize );
	}

	MSG_WriteByte( &buf, clc_EOF );
	CL_WriteBinaryMessage( &buf );
	Netchan_Transmit( &clc.netchan, buf.cursize, buf.data );

	// clients never really should have messages large enough
	// to fragment, but in case they do, fire them all off
	// at once
	// TTimo: this causes a packet burst, which is bad karma for winsock
	// added a WARNING message, we'll see if there are legit situations where this happens
	while ( clc.netchan.unsentFragments )
	{
		if ( cl_showSend->integer )
		{
			Com_Printf( "WARNING: unsent fragments (not supposed to happen!)" );
		}

		Netchan_TransmitNextFragment( &clc.netchan );
	}
}