Beispiel #1
0
qboolean Netchan_Validate(netchan_t *chan, qboolean *frag_message, unsigned int *fragid, int *frag_offset, int *frag_length)
{
	for (int i = 0; i < MAX_STREAMS; i++)
	{
		if (!frag_message[i])
			continue;

#ifndef REHLDS_FIXES
		if (FRAG_GETID(fragid[i]) > MAX_FRAGMENTS || FRAG_GETCOUNT(fragid[i]) > MAX_FRAGMENTS)
		{
			return FALSE;
		}

		if ((unsigned int)frag_length[i] > 0x800 || (unsigned int)frag_offset[i] > 0x4000)
		{
			return FALSE;
		}
#else // REHLDS_FIXES
		// total fragments should be <= MAX_FRAGMENTS and current fragment can't be > total fragments
		if (i == FRAG_NORMAL_STREAM && FRAG_GETCOUNT(fragid[i]) > MAX_NORMAL_FRAGMENTS)
			return FALSE;
		if (i == FRAG_FILE_STREAM && FRAG_GETCOUNT(fragid[i]) > MAX_FILE_FRAGMENTS)
			return FALSE;
		if (FRAG_GETID(fragid[i]) > FRAG_GETCOUNT(fragid[i]))
			return FALSE;
		if (!frag_length[i])
			return FALSE;
		if ((size_t)frag_length[i] > FRAGMENT_MAX_SIZE || (size_t)frag_offset[i] > NET_MAX_PAYLOAD - 1)
			return FALSE;

		int frag_end = frag_offset[i] + frag_length[i];

		// end of fragment is out of the packet
		if (frag_end + msg_readcount > net_message.cursize)
			return FALSE;

		// fragment overlaps next stream's fragment or placed after it
		for (int j = i + 1; j < MAX_STREAMS; j++)
		{
			if (frag_end > frag_offset[j] && frag_message[j]) // don't add msg_readcount for comparison
				return FALSE;
		}
#endif // REHLDS_FIXES
	}

	return TRUE;
}
Beispiel #2
0
bool NetChannel::CheckForCompletion(int stream, int intotalbuffers)
{
	int c;
	int size;
	int id;
	fragbuf_t *p;

	size = 0;
	c = 0;

	if (stream != FRAG_NORMAL_STREAM && stream != FRAG_FILE_STREAM) {
		m_System->DPrintf("ERROR! NetChannel::CheckForCompletion: invalid stream number %i.\n");
		return false;
	}

	p = m_incomingbufs[stream];
	if (!p) {
		return false;
	}

	while (p)
	{
		size += p->size;
		c++;

		id = FRAG_GETID(p->bufferId);
		if (id != c)
		{
			m_System->DPrintf("WARNING! NetChannel::CheckForCompletion: lost/dropped fragment Lost/dropped fragment would cause stall, retrying connection\n");
			m_crashed = true;
			return false;
		}

		p = p->next;
	}

	// Received final message
	if (c == intotalbuffers)
	{
		switch (stream)
		{
		case FRAG_NORMAL_STREAM:
			CopyNormalFragments();
			break;
		case FRAG_FILE_STREAM:
			m_System->Printf("TODO! NetChannel::CheckForCompletion: create file from fragments.\n");
			break;
		}

		return true;
	}

	return false;
}
Beispiel #3
0
void Netchan_AddBufferToList(fragbuf_t **pplist, fragbuf_t *pbuf)
{
	// Find best slot
	fragbuf_t *pprev, *n;
	int		id1, id2;

	pbuf->next = nullptr;

	if (!pplist)
		return;

	if (!*pplist)
	{
		pbuf->next = *pplist;
		*pplist = pbuf;
		return;
	}

	pprev = *pplist;
	while (pprev->next)
	{
		n = pprev->next; // Next item in list
		id1 = FRAG_GETID(n->bufferid);
		id2 = FRAG_GETID(pbuf->bufferid);

		if (id1 > id2)
		{
			// Insert here
			pbuf->next = n->next;
			pprev->next = pbuf;
			return;
		}

		pprev = pprev->next;
	}

	// Insert at end
	pprev->next = pbuf;
}
Beispiel #4
0
void Netchan_CheckForCompletion(netchan_t *chan, int stream, int intotalbuffers)
{
	int c;
	int size;
	int id;
	fragbuf_t *p;

	size = 0;
	c = 0;

	p = chan->incomingbufs[stream];
	if (!p)
		return;

	while (p)
	{
		size += p->frag_message.cursize;
		c++;

		id = FRAG_GETID(p->bufferid);
		if (id != c && chan == &g_pcls.netchan)
		{
			if (chan->sock == NS_MULTICAST)
			{
				char szCommand[32];
				Q_snprintf(szCommand, sizeof(szCommand), "listen %s\n", NET_AdrToString(chan->remote_address));
				Cbuf_AddText(szCommand);
				return;
			}
			Con_Printf("%s:  Lost/dropped fragment would cause stall, retrying connection\n", __func__);
			Cbuf_AddText("retry\n");
		}

		p = p->next;
	}

	// Received final message
	if (c == intotalbuffers)
	{
		chan->incomingready[stream] = true;
	}
}
Beispiel #5
0
/*
==============================
Netchan_CheckForCompletion

==============================
*/
void Netchan_CheckForCompletion( netchan_t *chan, int stream, int intotalbuffers )
{
	int	c, id;
	int	size;
	fragbuf_t	*p;

	size = 0;
	c = 0;

	p = chan->incomingbufs[stream];
	if( !p ) return;

	while( p )
	{
		size += BF_GetNumBytesWritten( &p->frag_message );
		c++;

		id = FRAG_GETID( p->bufferid );
		if( id != c )
		{
			if( chan->sock == NS_CLIENT )
			{
				MsgDev( D_ERROR, "Lost/dropped fragment would cause stall, retrying connection\n" );
				Cbuf_AddText( "reconnect\n" );
			}
		}
		p = p->next;
	}

	// received final message
	if( c == intotalbuffers )
	{
		chan->incomingready[stream] = true;
		MsgDev( D_NOTE, "\nincoming is complete %i bytes waiting\n", size );
	}
}
Beispiel #6
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;
}
Beispiel #7
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);
	}
}