Exemple #1
0
void Netchan_Transmit(netchan_t *chan, int length, byte *data)
{
#ifdef REHLDS_FIXES
	byte send_buf[MAX_UDP_PACKET];
#else
	byte send_buf[NET_MAX_MESSAGE];
#endif
	qboolean send_reliable;
	qboolean send_reliable_fragment;
	qboolean send_resending = false;
	unsigned w1, w2;
	int i, j;

	float fRate;

	sizebuf_t sb_send;
	sb_send.data = send_buf;
	sb_send.buffername = "Netchan_Transmit";
	sb_send.maxsize = sizeof(send_buf);
	sb_send.flags = 0;
	sb_send.cursize = 0;

	// check for message overflow
	if (chan->message.flags & 2) {
		Con_Printf("%s:Outgoing message overflow\n", NET_AdrToString(chan->remote_address));
		return;
	}

	// if the remote side dropped the last reliable message, resend it
	send_reliable = false;

	if (chan->incoming_acknowledged > chan->last_reliable_sequence &&
		chan->incoming_reliable_acknowledged != chan->reliable_sequence)
	{
		send_reliable = true;
		send_resending = true;
	}

	//
	// A packet can have "reliable payload + frag payload + unreliable payload
	// frag payload can be a file chunk, if so, it needs to be parsed on the receiving end and reliable payload + unreliable payload need
	// to be passed on to the message queue.  The processing routine needs to be able to handle the case where a message comes in and a file
	// transfer completes
	//
	//
	// if the reliable transmit buffer is empty, copy the current message out
	if (!chan->reliable_length)
	{
		qboolean send_frag = false;
		fragbuf_t *pbuf;

		// Will be true if we are active and should let chan->message get some bandwidth
		int		 send_from_frag[MAX_STREAMS] = { 0, 0 };
		int		 send_from_regular = 0;

#ifdef REHLDS_FIXES
		if (chan->message.cursize > MAX_MSGLEN)
		{
			Netchan_CreateFragments_(chan == &g_pcls.netchan ? 1 : 0, chan, &chan->message);
			SZ_Clear(&chan->message);
		}
#endif

		// If we have data in the waiting list(s) and we have cleared the current queue(s), then
		//  push the waitlist(s) into the current queue(s)
		Netchan_FragSend(chan);

		// Sending regular payload
		send_from_regular = (chan->message.cursize) ? 1 : 0;

		// Check to see if we are sending a frag payload
		//
		for (i = 0; i < MAX_STREAMS; i++)
		{
			if (chan->fragbufs[i])
			{
				send_from_frag[i] = 1;
			}
		}

		// Stall reliable payloads if sending from frag buffer
		if (send_from_regular && (send_from_frag[FRAG_NORMAL_STREAM]))
		{
			send_from_regular = false;

			// If the reliable buffer has gotten too big, queue it at the end of everything and clear out buffer
			//
			if (chan->message.cursize > MAX_RELIABLE_PAYLOAD)
			{
				Netchan_CreateFragments_(chan == &g_pcls.netchan ? 1 : 0, chan, &chan->message);
				SZ_Clear(&chan->message);
			}
		}

		// Startpos will be zero if there is no regular payload
		for (i = 0; i < MAX_STREAMS; i++)
		{
			chan->frag_startpos[i] = 0;

			// Assume no fragment is being sent
			chan->reliable_fragment[i] = 0;
			chan->reliable_fragid[i] = 0;
			chan->frag_length[i] = 0;

			if (send_from_frag[i])
			{
				send_frag = true;
			}
		}

		if (send_from_regular || send_frag)
		{
			chan->reliable_sequence ^= 1;
			send_reliable = true;
		}

		if (send_from_regular) {
#ifdef REHLDS_FIXES
			Q_memcpy(chan->reliable_buf, chan->message.data, chan->message.cursize);
#else
			Q_memcpy(chan->reliable_buf, chan->message_buf, chan->message.cursize);
#endif
			chan->reliable_length = chan->message.cursize;
			SZ_Clear(&chan->message);

			// If we send fragments, this is where they'll start
			for (i = 0; i < MAX_STREAMS; i++) {
				chan->frag_startpos[i] = chan->reliable_length;
			}
		}

		for (i = 0; i < MAX_STREAMS; i++) {
			int fragment_size;

			// Is there something in the fragbuf?
			pbuf = chan->fragbufs[i];

			fragment_size = 0; // Compiler warning.
			if (pbuf)
			{
				fragment_size = pbuf->frag_message.cursize;

				// Files set size a bit differently.
				if (pbuf->isfile && !pbuf->isbuffer)
				{
					fragment_size = pbuf->size;
				}
			}

			// Make sure we have enought space left
			if (send_from_frag[i] && pbuf && ((chan->reliable_length + fragment_size) < MAX_RELIABLE_PAYLOAD)) {

				chan->reliable_fragid[i] = MAKE_FRAGID(pbuf->bufferid, chan->fragbufcount[i]); // Which buffer are we sending?

				// If it's not in-memory, then we'll need to copy it in frame the file handle.
				if (pbuf->isfile && !pbuf->isbuffer)	{
					char compressedfilename[MAX_PATH];
					FileHandle_t hfile;
					if (pbuf->iscompressed)
					{
						Q_snprintf(compressedfilename, sizeof(compressedfilename), "%s.ztmp", pbuf->filename);
						hfile = FS_Open(compressedfilename, "rb");
					}
					else
					{
						hfile = FS_Open(pbuf->filename, "rb");
					}
					FS_Seek(hfile, pbuf->foffset, FILESYSTEM_SEEK_HEAD);
					FS_Read(&pbuf->frag_message.data[pbuf->frag_message.cursize], pbuf->size, 1, hfile);
					pbuf->frag_message.cursize += pbuf->size;
					FS_Close(hfile);
				}


				Q_memcpy(chan->reliable_buf + chan->reliable_length, pbuf->frag_message.data, pbuf->frag_message.cursize);
				chan->reliable_length += pbuf->frag_message.cursize;
				chan->frag_length[i] = pbuf->frag_message.cursize;


				// Unlink  pbuf
				Netchan_UnlinkFragment(pbuf, &chan->fragbufs[i]);

				chan->reliable_fragment[i] = 1;

				// Offset the rest of the starting positions
				for (j = i + 1; j < MAX_STREAMS; j++)
				{
					chan->frag_startpos[j] += chan->frag_length[i];
				}
			}
		}
	}

	// Prepare the packet header
	w1 = chan->outgoing_sequence | (send_reliable << 31);
	w2 = chan->incoming_sequence | (chan->incoming_reliable_sequence << 31);

	send_reliable_fragment = false;

	for (i = 0; i < MAX_STREAMS; i++)
	{
		if (chan->reliable_fragment[i])
		{
			send_reliable_fragment = true;
			break;
		}
	}

	if (send_reliable && send_reliable_fragment)
	{
		w1 |= (1 << 30);
	}

	chan->outgoing_sequence++;

	MSG_WriteLong(&sb_send, w1);
	MSG_WriteLong(&sb_send, w2);

	if (send_reliable && send_reliable_fragment)
	{
		for (i = 0; i < MAX_STREAMS; i++)
		{
			if (chan->reliable_fragment[i])
			{
				MSG_WriteByte(&sb_send, 1);
				MSG_WriteLong(&sb_send, chan->reliable_fragid[i]);
				MSG_WriteShort(&sb_send, chan->frag_startpos[i]);
				MSG_WriteShort(&sb_send, chan->frag_length[i]);
			}
			else
			{
				MSG_WriteByte(&sb_send, 0);
			}
		}
	}

	// Copy the reliable message to the packet first
	if (send_reliable) {
		SZ_Write(&sb_send, chan->reliable_buf, chan->reliable_length);
		chan->last_reliable_sequence = chan->outgoing_sequence - 1;
	}

	// Is there room for the unreliable payload?
	int max_send_size = MAX_ROUTEABLE_PACKET;
	if (!send_resending)
		max_send_size = sb_send.maxsize;

	if ((max_send_size - sb_send.cursize) >= length) {
		SZ_Write(&sb_send, data, length);
	}
	else {
		Con_DPrintf("Netchan_Transmit:  Unreliable would overfow, ignoring\n");
	}

	// Deal with packets that are too small for some networks
	if (sb_send.cursize < 16)	// Packet too small for some networks
	{
		// Go ahead and pad a full 16 extra bytes -- this only happens during authentication / signon
		for (int i = sb_send.cursize; i < 16; i++)
		{
			// Note that the server can parse svc_nop, too.
			MSG_WriteByte(&sb_send, svc_nop);
		}
	}

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

	if (!g_pcls.demoplayback)
	{
		COM_Munge2(sb_send.data + 8, sb_send.cursize - 8, (unsigned char)(chan->outgoing_sequence - 1));

		if (g_modfuncs.m_pfnProcessOutgoingNet)
			g_modfuncs.m_pfnProcessOutgoingNet(chan, &sb_send);

		NET_SendPacket(chan->sock, sb_send.cursize, sb_send.data, chan->remote_address);
	}

	if (g_psv.active && sv_lan.value != 0.0f && sv_lan_rate.value > MIN_RATE)
		fRate = 1.0 / sv_lan_rate.value;
	else
		fRate = 1.0 / chan->rate;

	if (chan->cleartime < realtime) {
		chan->cleartime = realtime;
	}

	chan->cleartime += (sb_send.cursize + UDP_HEADER_SIZE) * fRate;

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

		Con_Printf(" %c --> sz=%i seq=%i ack=%i rel=%i tm=%f\n"
				   , c
				   , sb_send.cursize
				   , chan->outgoing_sequence - 1
				   , chan->incoming_sequence
				   , send_reliable ? 1 : 0
				   , (float)(chan == &g_pcls.netchan ? g_pcl.time : g_psv.time));
	}
}
Exemple #2
0
void NetChannel::TransmitOutgoing()
{
	byte send_buf[NET_MAX_MESSAGE];
	BitBuffer data(send_buf, sizeof(send_buf));

	bool send_reliable;
	bool send_reliable_fragment;
	bool send_resending = false;
	unsigned w1, w2;
	int i, j;

	if (IsFakeChannel())
	{
		m_outgoing_sequence++;

		m_last_send = m_System->GetTime();
		m_cleartime = m_last_send + m_send_interval;

		m_reliableStream.FastClear();
		m_unreliableStream.FastClear();

		FakeAcknowledgement();
		return;
	}

	// check for reliable message overflow
	if (m_reliableStream.IsOverflowed())
	{
		m_System->DPrintf("Transmit:Outgoing m_reliableStream overflow (%s)\n", m_remote_address.ToString());
		m_reliableStream.Clear();
		return;
	}

	// check for unreliable message overflow
	if (m_unreliableStream.IsOverflowed())
	{
		m_System->DPrintf("Transmit:Outgoing m_unreliableStream overflow (%s)\n", m_remote_address.ToString());
		m_unreliableStream.Clear();
	}

	// if the remote side dropped the last reliable message, resend it
	send_reliable = false;

	if (m_incoming_acknowledged > m_last_reliable_sequence && m_incoming_reliable_acknowledged != m_reliable_sequence)
	{
		send_reliable = true;
		send_resending = true;
	}

	// A packet can have "reliable payload + frag payload + unreliable payload
	// frag payload can be a file chunk, if so, it needs to be parsed on the receiving end and reliable payload + unreliable payload need
	// to be passed on to the message queue. The processing routine needs to be able to handle the case where a message comes in and a file
	// transfer completes
	//
	// if the reliable transmit buffer is empty, copy the current message out
	if (!m_reliableOutSize)
	{
		bool send_frag = false;
		fragbuf_t *pbuf;

		// Will be true if we are active and should let chan->message get some bandwidth
		int send_from_frag[MAX_STREAMS] = { 0, 0 };
		int send_from_regular = 0;

		// If we have data in the waiting list(s) and we have cleared the current queue(s), then
		// push the m_waitlist(s) into the current queue(s)
		FragSend();

		// Sending regular payload
		send_from_regular = m_reliableStream.CurrentSize() ? 1 : 0;

		// Check to see if we are sending a frag payload
		for (i = 0; i < MAX_STREAMS; i++)
		{
			if (m_fragbufs[i])
			{
				send_from_frag[i] = 1;
			}
		}

		/*if (m_reliableStream.CurrentSize() > sizeof(send_buf))
		{
			CreateFragmentsFromBuffer(m_reliableStream.GetData(), m_reliableStream.CurrentSize(), FRAG_NORMAL_STREAM);
			m_reliableStream.FastClear();
		}*/

		// Stall reliable payloads if sending from frag buffer
		if (send_from_regular && (send_from_frag[FRAG_NORMAL_STREAM]))
		{
			send_from_regular = false;

			// If the reliable buffer has gotten too big, queue it at the end of everything and clear out buffer
			if (m_reliableStream.CurrentSize() > MAX_RELIABLE_PAYLOAD)
			{
				CreateFragmentsFromBuffer(m_reliableStream.GetData(), m_reliableStream.CurrentSize(), FRAG_NORMAL_STREAM);
				m_reliableStream.FastClear();
			}
		}

		// Startpos will be zero if there is no regular payload
		for (i = 0; i < MAX_STREAMS; i++)
		{
			m_frag_startpos[i] = 0;

			// Assume no fragment is being sent
			m_reliable_fragment[i] = 0;
			m_reliable_fragid[i] = 0;
			m_frag_length[i] = 0;

			if (send_from_frag[i])
			{
				send_frag = true;
			}
		}

		if (send_from_regular || send_frag)
		{
			m_reliable_sequence ^= 1u;
			send_reliable = true;
		}

		if (send_from_regular)
		{
			memcpy(m_reliableOutBuffer, m_reliableStream.GetData(), m_reliableStream.CurrentSize());

			m_reliableOutSize = m_reliableStream.CurrentSize();
			m_reliableStream.FastClear();

			// If we send fragments, this is where they'll start
			for (i = 0; i < MAX_STREAMS; i++) {
				m_frag_startpos[i] = m_reliableOutSize;
			}
		}

		for (i = 0; i < MAX_STREAMS; i++)
		{
			int fragment_size = 0;

			// Is there something in the fragbuf?
			pbuf = m_fragbufs[i];
			if (pbuf)
			{
				fragment_size = pbuf->size;

				// Files set size a bit differently.
				if (pbuf->isfile && !pbuf->isbuffer)
				{
					fragment_size = pbuf->size;
				}
			}

			// Make sure we have enought space left
			if (send_from_frag[i] && pbuf && (m_reliableOutSize + fragment_size) < MAX_RELIABLE_PAYLOAD)
			{
				m_reliable_fragid[i] = MAKE_FRAGID(pbuf->bufferId, m_fragbufcount[i]); // Which buffer are we sending?

				// If it's not in-memory, then we'll need to copy it in frame the file handle.
				if (pbuf->isfile && !pbuf->isbuffer) {
					m_System->Printf("TODO! NetChannel::Transmit: system file support\n");
				}

				memcpy(m_reliableOutBuffer + m_reliableOutSize, pbuf->data, pbuf->size);

				m_reliableOutSize += pbuf->size;
				m_frag_length[i] = pbuf->size;

				// Unlink pbuf
				UnlinkFragment(pbuf, i);
				m_reliable_fragment[i] = 1;

				// Offset the rest of the starting positions
				for (j = i + 1; j < MAX_STREAMS; j++)
				{
					m_frag_startpos[j] += m_frag_length[i];
				}
			}
		}
	}

	// Prepare the packet header
	w1 = m_outgoing_sequence | (send_reliable << 31);
	w2 = m_incoming_sequence | (m_incoming_reliable_sequence << 31);

	send_reliable_fragment = false;

	for (i = 0; i < MAX_STREAMS; i++)
	{
		if (m_reliable_fragment[i])
		{
			send_reliable_fragment = true;
			break;
		}
	}

	if (send_reliable && send_reliable_fragment) {
		w1 |= (1 << 30);
	}

	m_outgoing_sequence++;

	data.Clear();
	data.WriteLong(w1);
	data.WriteLong(w2);

	if (send_reliable && send_reliable_fragment)
	{
		for (i = 0; i < MAX_STREAMS; i++)
		{
			if (m_reliable_fragment[i])
			{
				data.WriteByte(1);
				data.WriteLong(m_reliable_fragid[i]);
				data.WriteShort(m_frag_startpos[i]);
				data.WriteShort(m_frag_length[i]);
			}
			else
			{
				data.WriteByte(0);
			}
		}
	}

	// Copy the reliable message to the packet first
	if (send_reliable) {
		data.WriteBuf(m_reliableOutBuffer, m_reliableOutSize);
		m_last_reliable_sequence = m_outgoing_sequence - 1;
	}

	// Is there room for the unreliable payload?
	int max_send_size = send_resending ? MAX_ROUTEABLE_PACKET : NET_MAX_MESSAGE;
	if ((max_send_size - data.CurrentSize()) >= m_unreliableStream.CurrentSize()) {
		data.ConcatBuffer(&m_unreliableStream);
	}
	else {
		m_System->DPrintf("WARNING! TransmitOutgoing: Unreliable would overfow, ignoring.\n");
	}

	m_unreliableStream.FastClear();

	// Deal with packets that are too small for some networks
	// Packet too small for some networks
	if (data.CurrentSize() < 16)
	{
		// Go ahead and pad a full 16 extra bytes -- this only happens during authentication / signon
		for (int i = data.CurrentSize(); i < 16; i++)
		{
			// Note that the server can parse svc_nop, too.
			data.WriteByte(svc_nop);
		}
	}

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

	COM_Munge2(data.GetData() + 8, data.CurrentSize() - 8, (unsigned char)(m_outgoing_sequence - 1));

	if (m_Socket) {
		m_Socket->SendPacket(&m_remote_address, data.GetData(), data.CurrentSize());
	}

	m_last_send = m_System->GetTime();
	m_cleartime = max(m_send_interval, (data.CurrentSize() + UDP_HEADER_SIZE) * (1.0 / m_max_bandwidth_rate)) + m_last_send;
}