Ejemplo n.º 1
0
qboolean Netchan_Process(netchan_t *chan)
{
	int				i;
	unsigned int	sequence, sequence_ack;
	unsigned int	reliable_ack, reliable_message;
	unsigned int	fragid[MAX_STREAMS] = { 0, 0 };
	qboolean		frag_message[MAX_STREAMS] = { false, false };
	int				frag_offset[MAX_STREAMS] = { 0, 0 };
	int				frag_length[MAX_STREAMS] = { 0, 0 };
	qboolean		message_contains_fragments;


	if (!g_pcls.demoplayback && !g_pcls.passive)
	{
		if (!NET_CompareAdr(net_from, chan->remote_address))
			return FALSE;
	}

	chan->last_received = realtime;

	// get sequence numbers
	MSG_BeginReading();
	sequence = MSG_ReadLong();
	sequence_ack = MSG_ReadLong();

	if (sequence_ack & 0x40000000)
	{
		if (!g_modfuncs.m_pfnProcessIncomingNet)
			return FALSE;
	}

	if (g_modfuncs.m_pfnProcessIncomingNet)
	{
		if (!g_modfuncs.m_pfnProcessIncomingNet(chan, &net_message))
			return FALSE;
	}

	reliable_message = sequence >> 31;
	reliable_ack = sequence_ack >> 31;
	message_contains_fragments = sequence & (1 << 30) ? true : false;

	COM_UnMunge2(&net_message.data[8], net_message.cursize - 8, sequence & 0xFF);
	if (message_contains_fragments)
	{
		for (i = 0; i < MAX_STREAMS; i++)
		{
			if (MSG_ReadByte())
			{
				frag_message[i] = true;
				fragid[i] = MSG_ReadLong();
				frag_offset[i] = MSG_ReadShort();
				frag_length[i] = MSG_ReadShort();
			}
		}

		if (!Netchan_Validate(chan, frag_message, fragid, frag_offset, frag_length))
			return FALSE;
	}

	sequence &= ~(1 << 31);
	sequence &= ~(1 << 30);
	sequence_ack &= ~(1 << 31);
	sequence_ack &= ~(1 << 30);

	if (net_showpackets.value != 0.0 && net_showpackets.value != 3.0)
	{
		char c = (chan == &g_pcls.netchan) ? 'c' : 's';

		Con_Printf(
			" %c <-- sz=%i seq=%i ack=%i rel=%i tm=%f\n",
			c,
			net_message.cursize,
			sequence,
			sequence_ack,
			reliable_message,
			(chan == &g_pcls.netchan) ? g_pcl.time : g_psv.time);
	}

	if (sequence <= (unsigned)chan->incoming_sequence)
	{
		if (net_showdrop.value != 0.0) {
			if (sequence == (unsigned)chan->incoming_sequence)
				Con_Printf("%s:duplicate packet %i at %i\n", NET_AdrToString(chan->remote_address), sequence, chan->incoming_sequence);
			else
				Con_Printf("%s:out of order packet %i at %i\n", NET_AdrToString(chan->remote_address), sequence, chan->incoming_sequence);
		}
		return FALSE;
	}

	//
	// dropped packets don't keep the message from being used
	//
	net_drop = sequence - (chan->incoming_sequence + 1);
	if (net_drop > 0 && net_showdrop.value != 0.0)
	{
		Con_Printf("%s:Dropped %i packets at %i\n", NET_AdrToString(chan->remote_address), net_drop, sequence);
	}

	//
	// if the current outgoing reliable message has been acknowledged
	// clear the buffer to make way for the next
	//
	if (reliable_ack == (unsigned)chan->reliable_sequence)
	{
		// Make sure we actually could have ack'd this message
#ifdef REHLDS_FIXES
		if (sequence_ack >= (unsigned)chan->last_reliable_sequence)
#else // REHLDS_FIXES
		if (chan->incoming_acknowledged + 1 >= chan->last_reliable_sequence)
#endif // REHLDS_FIXES
		{
			chan->reliable_length = 0;	// it has been received
		}
	}

	//
	// if this message contains a reliable message, bump incoming_reliable_sequence
	//
	chan->incoming_sequence = sequence;
	chan->incoming_acknowledged = sequence_ack;
	chan->incoming_reliable_acknowledged = reliable_ack;
	if (reliable_message)
	{
		chan->incoming_reliable_sequence ^= 1;
	}

	int statId = chan->flow[FLOW_INCOMING].current & 0x1F;
	chan->flow[FLOW_INCOMING].stats[statId].size = net_message.cursize + UDP_HEADER_SIZE;
	chan->flow[FLOW_INCOMING].stats[statId].time = realtime;
	chan->flow[FLOW_INCOMING].current++;
	Netchan_UpdateFlow(chan);

	if (message_contains_fragments)
	{
		for (i = 0; i < MAX_STREAMS; i++)
		{
			int j;
			fragbuf_t *pbuf;
			int inbufferid;
			int intotalbuffers;

			if (!frag_message[i])
				continue;

			inbufferid = FRAG_GETID(fragid[i]);
			intotalbuffers = FRAG_GETCOUNT(fragid[i]);

			if (fragid[i] != 0)
			{
				pbuf = Netchan_FindBufferById(&chan->incomingbufs[i], fragid[i], true);
				if (pbuf) {
					int len = frag_length[i];
					SZ_Clear(&pbuf->frag_message);
					SZ_Write(&pbuf->frag_message, &net_message.data[msg_readcount + frag_offset[i]], len);
				}
				else {
					Con_Printf("Netchan_Process:  Couldn't allocate or find buffer %i\n", inbufferid);
				}
				// Count # of incoming bufs we've queued? are we done?
				Netchan_CheckForCompletion(chan, i, intotalbuffers);
			}

			// Rearrange incoming data to not have the frag stuff in the middle of it
			int wpos = msg_readcount + frag_offset[i];
			int rpos = wpos + frag_length[i];

			Q_memmove(net_message.data + wpos, net_message.data + rpos, net_message.cursize - rpos);
			net_message.cursize -= frag_length[i];

			for (j = i + 1; j < MAX_STREAMS; j++)
			{
				frag_offset[j] -= frag_length[i]; // fragments order already validated
			}
		}

		// Is there anything left to process?
		if (net_message.cursize <= 16)
			return FALSE;
	}

	return TRUE;
}
Ejemplo n.º 2
0
void NetChannel::ProcessIncoming(unsigned char *data, int size)
{
	BitBuffer message(data, size);

	int i;
	unsigned int sequence, sequence_ack;
	unsigned int reliable_ack, reliable_message;
	unsigned int fragid[MAX_STREAMS] = { 0, 0 };

	bool frag_message[MAX_STREAMS] = { false, false };
	int frag_offset[MAX_STREAMS] = { 0, 0 };
	int frag_length[MAX_STREAMS] = { 0, 0 };

	bool message_contains_fragments;
	int net_drop;
	float newLoss;
	float weight;

	// get sequence numbers
	sequence = message.ReadLong();
	if (sequence == CONNECTIONLESS_HEADER)
	{
		NetPacket *p = new NetPacket;

		p->connectionless = true;
		p->time = m_System->GetTime();
		p->seqnr = -1;

		p->address.FromNetAddress(&m_remote_address);
		p->data.Resize(size - 4);
		p->data.WriteBuf(data + 4, size - 4);
		p->data.Reset();

		m_incomingPackets.AddHead(p);
		return;
	}

	if (!m_connected) {
		return;
	}

	sequence_ack = message.ReadLong();

	COM_UnMunge2(message.GetData() + 8, size - 8, sequence & 0xFF);

	reliable_message = sequence >> 31;
	reliable_ack = sequence_ack >> 31;
	message_contains_fragments = sequence & (1 << 30) ? true : false;

	// TODO: Looks like need to move it above COM_UnMunge2
	if (sequence_ack & 0x40000000)
	{
		m_crashed = true;
		return;
	}

	if (message_contains_fragments)
	{
		for (i = 0; i < MAX_STREAMS; i++)
		{
			if (message.ReadByte())
			{
				frag_message[i] = true;
				fragid[i] = message.ReadLong();
				frag_offset[i] = message.ReadShort();
				frag_length[i] = message.ReadShort();
			}
		}
	}

	sequence &= ~(1 << 31);
	sequence &= ~(1 << 30);

	sequence_ack &= ~(1 << 31);
	sequence_ack &= ~(1 << 30);

	if (sequence <= (unsigned int)m_incoming_sequence)
	{
		if (sequence == (unsigned int)m_incoming_sequence)
			m_System->DPrintf("NetChannel::ProcessIncoming: duplicate packet %i at %i from %s\n", sequence, m_incoming_sequence, m_remote_address.ToString());
		else
			m_System->DPrintf("NetChannel::ProcessIncoming: out of order packet %i at %i from %s\n", sequence, m_incoming_sequence, m_remote_address.ToString());

		return;
	}

	// dropped packets don't keep the message from being used
	net_drop = sequence - (m_incoming_sequence + 1);
	if (net_drop < 0) {
		net_drop = 0;
	}

	newLoss = (net_drop + 1) * (1.0f / 200.0f);
	if (newLoss < 1.0f)
	{
		weight = (float)net_drop / (float)(net_drop + 1);
		m_loss = (1.0 - newLoss) * m_loss + weight * newLoss;
	}
	else
		m_loss = 1;

	// if the current outgoing reliable message has been acknowledged
	// clear the buffer to make way for the next
	if (reliable_ack == (unsigned int)m_reliable_sequence)
	{
		if (m_incoming_acknowledged + 1 >= m_last_reliable_sequence)
		{
			// it has been received
			m_reliableOutSize = 0;
		}
	}

	// if this message contains a reliable message, bump incoming_reliable_sequence
	m_incoming_sequence = sequence;
	m_incoming_acknowledged = sequence_ack;
	m_incoming_reliable_acknowledged = reliable_ack;

	if (reliable_message) {
		m_incoming_reliable_sequence ^= 1u;
	}

	int statId = m_flow[FLOW_INCOMING].current & 0x1f;
	m_flow[FLOW_INCOMING].stats[statId].size = size + UDP_HEADER_SIZE;
	m_flow[FLOW_INCOMING].stats[statId].time = m_System->GetTime();
	m_flow[FLOW_INCOMING].current++;

	m_last_received = m_System->GetTime();

	if (message_contains_fragments)
	{
		for (i = 0; i <= 1; ++i)
		{
			int j;
			fragbuf_t *pbuf;
			int inbufferid;
			int intotalbuffers;

			if (!frag_message[i])
				continue;

			inbufferid = FRAG_GETID(fragid[i]);
			intotalbuffers = FRAG_GETCOUNT(fragid[i]);

			if (fragid[i])
			{
				pbuf = FindBufferById(&m_incomingbufs[i], fragid[i], true);
				if (pbuf)
				{
					memcpy(pbuf->data, message.GetData() + message.CurrentSize() + frag_offset[i], frag_length[i]);
					pbuf->size = frag_length[i];
				}
				else
				{
					m_System->Printf("NetChannel::ProcessIncoming: couldn't allocate or find buffer %i\n", inbufferid);
				}

				// Count # of incoming bufs we've queued? are we done?
				CheckForCompletion(i, intotalbuffers);
			}

			// Rearrange incoming data to not have the frag stuff in the middle of it
			int wpos = message.CurrentSize() + frag_offset[i];
			int rpos = wpos + frag_length[i];

			memmove(message.GetData() + wpos, message.GetData() + rpos, message.GetMaxSize() - rpos);
			message.m_MaxSize -= frag_length[i];

			for (j = i + 1; j < MAX_STREAMS; j++)
			{
				// fragments order already validated
				frag_offset[j] -= frag_length[i];
			}
		}
	}

	int curLen = message.GetMaxSize() - message.CurrentSize();
	if (curLen > 0)
	{
		NetPacket *p = new NetPacket;
		p->connectionless = 0;
		p->hasReliableData = reliable_message != 0;
		p->time = m_System->GetTime();
		p->seqnr = m_incoming_sequence;
		p->address.FromNetAddress(&m_remote_address);
		p->data.Resize(curLen);
		p->data.WriteBuf(message.m_CurByte, curLen);
		p->data.Reset();
		m_incomingPackets.AddHead(p);
	}
}