⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trackernet.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//=========== (C) Copyright 2000 Valve, L.L.C. All rights reserved. ===========
//
// The copyright to the contents herein is the property of Valve, L.L.C.
// The contents may be used and/or copied only with the written permission of
// Valve, L.L.C., or in accordance with the terms and conditions stipulated in
// the agreement/contract under which the contents have been supplied.
//
// Purpose: 
//=============================================================================

#include "PacketHeader.h"
#include "ReceiveMessage.h"
#include "Random.h"
#include "SendMessage.h"
#include "Sockets.h"
#include "Threads.h"
#include "ThreadedSocket.h"
#include "TrackerNET_Interface.h"
#include "TrackerProtocol.h"
#include "UtlLinkedList.h"
#include "UtlRBTree.h"

#include <math.h>
#include <stdarg.h>
#include <time.h>
#include <assert.h>
#include <stdio.h>

#pragma warning(disable: 4244)  // warning C4244: 'argument' : conversion from 'int' to 'unsigned char', possible loss of data
								// disabled for the CUtlLinkedList that uses an unsigned char as it's index
#pragma warning(disable: 4710)	// warning C4710: function not expanded

// networking constants
static const float ACK_DELAY = 0.2f;
static const float RESEND_TIME = 1.5f;		// time before resending an unacknowledged packet
static const int   MAX_SEND_ATTEMPTS = 5;	// max number of times a packet is sent before we fail
static const int   MESSAGE_WINDOW = 16;		// range of packets to hold in sliding message window

// used for mapping ip's to targets
struct TargetMapItem_t
{
	CNetAddress netAddress;
	int targetIndex;
};

//-----------------------------------------------------------------------------
// Purpose: implementation of the trackerNet interface
//-----------------------------------------------------------------------------
class CTrackerNET : public ITrackerNET
{
public:
	CTrackerNET();
	~CTrackerNET();

	// sets up the networking thread and the port to listen on
	bool Initialize(unsigned short portMin, unsigned short portMax);
	// closes the network; if flush is true, then it blocks until the worker threads have completed
	void Shutdown(bool flush);

	void RunFrame();

	// message receiving
	IReceiveMessage *GetIncomingData();		// Gets any info has been received, returns NULL if no more
	IReceiveMessage *GetFailedMessage();
	void ReleaseMessage(IReceiveMessage *); // frees a received message

	IBinaryBuffer *GetIncomingRawData(CNetAddress &address);	// gets any info that has been received from out-of-band engine packets
	IBinaryBuffer *CreateRawMessage();
	void SendRawMessage(IBinaryBuffer *message, CNetAddress &address);

	// message sending
	ISendMessage *CreateMessage(int msgID);
	ISendMessage *CreateMessage(int msgID, void const *pBuf, int bufSize);
	ISendMessage *CreateReply(int msgID, IReceiveMessage *msgToReplyTo);
	void SendMessage(ISendMessage *pMsg, Reliability_e state);

	// network addresses
	CNetAddress GetNetAddress(const char *stringAddress);
	CNetAddress GetLocalAddress();

	// thread API access
	IThreads *GetThreadAPI();
	int GetPort();

	virtual void deleteThis()
	{
		delete this;
	}

	// returns the number of buffers current in the input and output queues
	int BuffersInQueue();
	int PeakBuffersInQueue();
	int BytesSent();
	int BytesReceived();
	int BytesSentPerSecond();
	int BytesReceivedPerSecond();

	void SetWindowsEvent(unsigned long event);

private:
	// connection creation
	struct NetworkTarget_t;
	int FindTarget(CNetAddress &address, int targetID = -1, int sequenceNumber = -1);
	void InternalSendMessage(ISendMessage *pMsg, NetworkTarget_t *target, int sequenceNumber);
	void ParseIncomingPacket(IBinaryBuffer *packet, CNetAddress netAddress, bool encrypted);
	void CheckReliablePacketSending();
	void CheckSendingAcknowledgements();
	void UpdateSequence(NetworkTarget_t *target, int targetIndex, int incomingSequence);
	void HandleOutOfSequencePacket(IBinaryBuffer *packet, packet_header_t *pHeader, NetworkTarget_t *target, CNetAddress &netAddress, bool encrypted);

	int FindTargetIndexByAddress(CNetAddress &addr);
	
#ifdef _DEBUG
	// debug utility function
	void WriteToLog(const char *str, ...);
#else
	void WriteToLog(const char *str, ...) {}
#endif
	// pointers to our networking interfaces
	IThreadedSocket *m_pThreadedSocket;
	IThreads *m_pThreads;
	ISockets *m_pSockets;

	float m_flNextFrameTime;	// next time at which we should Run a frame

	unsigned long m_hEvent;		// handle to event to signal

	// holds a single sent message, in case it has to be resent
	struct SentMessage_t
	{
		int sequenceNumber;
		float resendTime;		// time to resend (in seconds)
		int resendAttempt;		// the number of resends sent
		int networkTargetHandle;	// handle to the network target this was sent from
		int networkTargetID;
		ISendMessage *message;
	};

	// holds messages we are received, but not ready to use
	struct FutureMessage_t
	{
		int sequenceNumber;
		IReceiveMessage *message;
	};

	// target list
	struct NetworkTarget_t
	{
		NetworkTarget_t() : m_MessageWindow(MESSAGE_WINDOW, 0) {}

		CNetAddress netAddress;
		int targetID;				// unique identifier of this connection

		int incomingSequence;		// the highest valid ID received from the target
		int incomingAcknowledged;	// the highest valid ID received from the target that we have sent an acknowledgement to

		int outgoingSequence;		// the highest (most recent) packet ID sent
		int outgoingAcknowledged;	// the highest packet ID that has been ack'd by the target
									// packets in the range (outgoingAcknowledged, outgoingSequence] will get auto-resent

		float ackTime;				// time at which the next ack can be sent
		bool needAck;				// true if an ack has been marked to be send

//		float createTime;			// time at which this connection was created (unused)
//		float activityTime;			// time at which there was last activity on this connection (unused for now)
		
		CUtlLinkedList<FutureMessage_t, unsigned char> m_MessageWindow;
	};

	// index-based linked list of network targets - essentially safe handles to targets
	CUtlLinkedList<NetworkTarget_t, int> m_TargetList;
	int m_iHighestAckTarget;

	// list of messages sent reliably, and may need to be resent
	CUtlLinkedList<SentMessage_t, int> m_ReliableMessages;

	// map to the targets
	CUtlRBTree<TargetMapItem_t, int> m_TargetMap;

	// holds the list of all failed messages
	struct FailedMsg_t
	{
		IReceiveMessage *message;
	};
	CUtlLinkedList<FailedMsg_t, int> m_FailedMsgs;

	// messages that we've received, in order
	struct ReceivedMsg_t
	{
		IReceiveMessage *message;
	};
	CUtlLinkedList<ReceivedMsg_t, int> m_ReceivedMsgs;
};

EXPOSE_INTERFACE(CTrackerNET, ITrackerNET, TRACKERNET_INTERFACE_VERSION);

//-----------------------------------------------------------------------------
// Purpose: comparison function for TargetMapItem_t
//-----------------------------------------------------------------------------
bool TargetMapLessFunc(const TargetMapItem_t &t1, const TargetMapItem_t &t2)
{
	return (t1.netAddress < t2.netAddress);
}

//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CTrackerNET::CTrackerNET()
{
	m_flNextFrameTime = 0.0f;
	m_iHighestAckTarget = -1;
	m_hEvent = 0;

	m_TargetMap.SetLessFunc(TargetMapLessFunc);
}

//-----------------------------------------------------------------------------
// Purpose: Destructor
//-----------------------------------------------------------------------------
CTrackerNET::~CTrackerNET()
{
	if (m_pThreadedSocket)
	{
		m_pThreadedSocket->deleteThis();
		m_pThreadedSocket = NULL;
	}
}

//-----------------------------------------------------------------------------
// Purpose: Sets up the networking
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CTrackerNET::Initialize(unsigned short portMin, unsigned short portMax)
{
	// initialize threading
	CreateInterfaceFn factory = Sys_GetFactoryThis();
	m_pThreads = (IThreads *)factory(THREADS_INTERFACE_VERSION, NULL);

	// initialize socket layer
	m_pThreadedSocket = (IThreadedSocket *)factory(THREADEDSOCKET_INTERFACE_VERSION, NULL);
	m_pSockets = m_pThreadedSocket->GetSocket();
	if (!m_pSockets->InitializeSockets(portMin, portMax))
		return false;

	return true;
}

//-----------------------------------------------------------------------------
// Purpose: closes and shutsdown the network
// Input  : flush - if flush is true, then it blocks until the worker threads have completed
//-----------------------------------------------------------------------------
void CTrackerNET::Shutdown(bool flush)
{
	m_pThreadedSocket->Shutdown(flush);

	m_pThreadedSocket->deleteThis();
	m_pThreadedSocket = NULL;
}

//-----------------------------------------------------------------------------
// Purpose: Runs a networking frame, handling reliable packet delivery
//-----------------------------------------------------------------------------
void CTrackerNET::RunFrame()
{
	float time = (float)m_pThreads->GetTime();

	// don't Run the frame more than 20 times per second
	if (time < m_flNextFrameTime)
		return;

	m_flNextFrameTime = time + 0.05f;

	// read in any new packets
	IBinaryBuffer *recvBuf = NULL;
	bool encrypted = false;
	CNetAddress address;

	// don't read too many packets in one frame
	int packetsToRead = 10;
	while (m_pThreadedSocket->GetNewMessage(&recvBuf, &address, encrypted) && packetsToRead--)
	{
		ParseIncomingPacket(recvBuf, address, encrypted);
	}

	// check to see if we need to send any ack packets in response to reliable messages we've received
	CheckSendingAcknowledgements();

	// see if any of our packets need to be resent
	CheckReliablePacketSending();
}

//-----------------------------------------------------------------------------
// Purpose: Checks to see if we need to send any ack packets 
//			in response to reliable messages we've received
//-----------------------------------------------------------------------------
void CTrackerNET::CheckSendingAcknowledgements()
{
	float time = (float)m_pThreads->GetTime();

	// the target list is in order of ackTime's
	while (m_TargetList.Count())
	{
		int targetIndex = m_TargetList.Head();
		NetworkTarget_t &target = m_TargetList[targetIndex];

		if (!target.needAck)
			break;	// target does not need acknowledging, we're at the end of the list

		if (target.ackTime > time)
			break;	// this packet not yet ready to be acknowledged

		if (target.incomingSequence > target.incomingAcknowledged)
		{
			// send an acknowledgement
			ISendMessage *pMsg = CreateMessage(TMSG_ACK);
			pMsg->SetNetAddress(target.netAddress);
			SendMessage(pMsg, NET_UNRELIABLE);
		}

		// this target has been acknowledged, move to the end of the list
		target.needAck = false;
		m_TargetList.Unlink(targetIndex);
		m_TargetList.LinkToTail(targetIndex);

		// check to see if the highest ack target needs to be reset
		if (targetIndex == m_iHighestAckTarget)
		{
			m_iHighestAckTarget = -1;
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Checks to see if we should resend any reliable packets
//-----------------------------------------------------------------------------
void CTrackerNET::CheckReliablePacketSending()
{
	float time = m_pThreads->GetTime();

	// reliable packets are held in the m_ReliableMessages queue in the order that they were sent
	// if a packet is resent, it is moved to the end of the queue
	// packets are also checked at this time to see if they have been acknowledged
	while (m_ReliableMessages.Count())
	{
		// get the first message
		int index = m_ReliableMessages.Head();

		// get the message
		SentMessage_t &msg = m_ReliableMessages[index];

		// check the resend time, if it's not time to resend then we have nothing more to do 
		if (msg.resendTime > time)
			break;	

		// get the network target for this message
		if (!m_TargetList.IsValidIndex(msg.networkTargetHandle) 
			|| !m_TargetList.IsInList(msg.networkTargetHandle) 
			|| m_TargetList[msg.networkTargetHandle].targetID != msg.networkTargetID)
		{
			// message's target has been removed, kill
			if (msg.message)
			{
				msg.message->deleteThis();
			}
			m_ReliableMessages.Remove(index);
			continue;
		}

		NetworkTarget_t &target = m_TargetList[msg.networkTargetHandle];

		// check to see if it's already been acknowledged
		if (msg.sequenceNumber <= target.outgoingAcknowledged)
		{
			// message has been acknowledged, kill
			if (msg.message)
			{
				msg.message->deleteThis();
			}
			m_ReliableMessages.Remove(index);

			// move onto next message
			continue;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -