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

📄 usersession.cpp

📁 hl2 source code. Do not use it illegal.
💻 CPP
📖 第 1 页 / 共 4 页
字号:
	else
	{
		// user is behind a firewall; queue the packet until they heartbeat us again
		int bufferSize = SendMessage->MsgSize();
		bufferedmsg_t *msg = AllocateMessageBuffer(bufferSize);
		msg->msgID = SendMessage->GetMsgID();
		SendMessage->ReadMsgIntoBuffer(msg->data, bufferSize);
		AddBufferToQueue(msg);

		// release the send message
		SendMessage->deleteThis();
	}
}

//-----------------------------------------------------------------------------
// Purpose: message to user has failed, either the user has crashed or the firewall is blocking
//-----------------------------------------------------------------------------
void CUserSession::OnFailedMessage(IReceiveMessage *failedMsg)
{
	float currentTime = sessionmanager()->GetCurrentTime();

	// make sure we shouldn't be timed out
	if (CheckForTimeout(currentTime))
		return;

	// calculate the time at which we know the firewall fails, with a little slop
	float timeSinceAccess = currentTime - m_flLastAccess;
	// subtract out the time it takes a message to fail
	timeSinceAccess -= 6.0f;

	if (m_flFirewallWindow > timeSinceAccess)
	{
		// the firewall window has shrunk
		m_flFirewallWindow = timeSinceAccess;
		m_bUpdateFirewallWindowToClient = true;
	}

	if (m_flFirewallWindow < MINIMUM_FIRWALL_WINDOW_DURATION)
	{
		// firewall window is too small, just kill the user
		Logoff(true, false, false);
		return;
	}

	// extract the message, add it to the message queue
	int bufferSize = failedMsg->MsgSize();
	bufferedmsg_t *msg = AllocateMessageBuffer(bufferSize);
	msg->msgID = failedMsg->GetMsgID() - TMSG_FAIL_OFFSET;
	failedMsg->ReadMsgIntoBuffer(msg->data, bufferSize);
	AddBufferToQueue(msg);
}

enum
{
	MEMPOOL_SIZE_SMALL = 128,
	MEMPOOL_SIZE_MEDIUM = 256,
	MEMPOOL_SIZE_LARGE = 512,
};

CMemoryPool g_SmallMsgMemPool(MEMPOOL_SIZE_SMALL, 256);
CMemoryPool g_MediumMsgMemPool(MEMPOOL_SIZE_MEDIUM, 256);
CMemoryPool g_LargeMsgMemPool(MEMPOOL_SIZE_LARGE, 256);

static int g_AllocCounts[4] = { 0 };

//-----------------------------------------------------------------------------
// Purpose: returns a block of memory from the appropriate mempool
//-----------------------------------------------------------------------------
CUserSession::bufferedmsg_t *CUserSession::AllocateMessageBuffer(int bufferSize)
{
	int allocSize = bufferSize + sizeof(bufferedmsg_t);

	// find the mempool of the appropriate size
	bufferedmsg_t *buffer = NULL;
	if (allocSize <= MEMPOOL_SIZE_SMALL)
	{
		buffer = (bufferedmsg_t *)g_SmallMsgMemPool.Alloc(allocSize);
		g_AllocCounts[0]++;
	}
	else if (allocSize <= MEMPOOL_SIZE_MEDIUM)
	{
		buffer = (bufferedmsg_t *)g_MediumMsgMemPool.Alloc(allocSize);
		g_AllocCounts[1]++;
	}
	else if (allocSize <= MEMPOOL_SIZE_LARGE)
	{
		buffer = (bufferedmsg_t *)g_LargeMsgMemPool.Alloc(allocSize);
		g_AllocCounts[2]++;
	}
	else
	{
		// too large, just allocate from heap
		buffer = (bufferedmsg_t *)malloc(allocSize);
		g_AllocCounts[3]++;
	}

	buffer->dataSize = bufferSize;
	return buffer;
}

//-----------------------------------------------------------------------------
// Purpose: free's the memory for a message buffer
//-----------------------------------------------------------------------------
void CUserSession::FreeMessageBuffer(bufferedmsg_t *msg)
{
	int allocSize = msg->dataSize + sizeof(bufferedmsg_t);

	// find the mempool of the appropriate size
	if (allocSize <= MEMPOOL_SIZE_SMALL)
	{
		g_SmallMsgMemPool.Free(msg);
	}
	else if (allocSize <= MEMPOOL_SIZE_MEDIUM)
	{
		g_MediumMsgMemPool.Free(msg);
	}
	else if (allocSize <= MEMPOOL_SIZE_LARGE)
	{
		g_LargeMsgMemPool.Free(msg);
	}
	else
	{
		// too large, will have used heap
		free(msg);
	}
}

//-----------------------------------------------------------------------------
// Purpose: adds a message buffer to the end of the queue
//-----------------------------------------------------------------------------
void CUserSession::AddBufferToQueue(bufferedmsg_t *msg)
{
	g_pConsole->Print(6, "Queueing message '%d' for '%d' (size: %d)\n", msg->msgID, m_iUserID, msg->dataSize);

	if (!m_pMsgQueueLast)
	{
		assert(!m_pMsgQueueFirst);

		// nothing in queue yet, add to Start
		m_pMsgQueueFirst = msg;
		m_pMsgQueueLast = msg;
		msg->nextBuffer = NULL;
		return;
	}

	// add to the end of the list
	msg->nextBuffer = NULL;
	m_pMsgQueueLast->nextBuffer = msg;
	m_pMsgQueueLast = msg;
}

//-----------------------------------------------------------------------------
// Purpose: sends all the messages in the queue, then releases them
//-----------------------------------------------------------------------------
void CUserSession::SendQueuedMessages()
{
	if (m_pMsgQueueFirst)
	{
		g_pConsole->Print(6, "Sending queued messages to '%d'\n", m_iUserID);
	}

	// iterate through and send all the messages
	for (bufferedmsg_t *msg = m_pMsgQueueFirst; msg != NULL; msg = msg->nextBuffer)
	{
		ISendMessage *sendMsg = net()->CreateMessage(msg->msgID, msg->data, msg->dataSize);
		sendMsg->SetSessionID(m_iSessionID);
		sendMsg->SetNetAddress(m_NetAddress);
		sendMsg->SetEncrypted(true);

		net()->SendMessage(sendMsg, NET_RELIABLE);
	}
	
	// clear out the queue
	FlushMessageQueue();
}

//-----------------------------------------------------------------------------
// Purpose: throws away the current message queue
//-----------------------------------------------------------------------------
void CUserSession::FlushMessageQueue()
{
	// free all the messages
	bufferedmsg_t *msg = m_pMsgQueueFirst;
	while (msg)
	{
		bufferedmsg_t *nextMsg = msg->nextBuffer;
		FreeMessageBuffer(msg);
		msg = nextMsg;
	}

	m_pMsgQueueFirst = NULL;
	m_pMsgQueueLast = NULL;
}

//-----------------------------------------------------------------------------
// Purpose: data accessor
//-----------------------------------------------------------------------------
unsigned int CUserSession::IP( void )
{
	return m_NetAddress.IP();
}

//-----------------------------------------------------------------------------
// Purpose: data accessor
//-----------------------------------------------------------------------------
unsigned int CUserSession::Port( void )
{
	return m_NetAddress.Port();
}

//-----------------------------------------------------------------------------
// Purpose: Constructs the data from specifying a users' details
//			returns the number of bytes written
//-----------------------------------------------------------------------------
int CUserSession::ConstructFriendsStatusMessageData(void const *usersArray, int userCount, unsigned int *destBuffer)
{
	ITrackerUserDatabase::user_t *users = (ITrackerUserDatabase::user_t *)usersArray;

	int intsWritten = 0;
	for (int i = 0; i < userCount; i++)
	{
		// write in ID first
		destBuffer[intsWritten++] = users[i].userID;

		// write status second
		destBuffer[intsWritten++] = users[i].userStatus;

		// write session id third
		destBuffer[intsWritten++] = users[i].userSessionID;

		// write IP address
		destBuffer[intsWritten++] = users[i].userIP;
		destBuffer[intsWritten++] = users[i].userPort;

		// write serverID
		// BACKWARDS COMPATIBILITY: don't send serverID to old clients
		if (m_iBuildNum >= COMPATILIBITY_SERVERID_SUPPORT_VERSION_MIN)
		{
			destBuffer[intsWritten++] = users[i].userServerID;
		}
	}
	return intsWritten * sizeof(int);
}

//-----------------------------------------------------------------------------
// Purpose: Handles results from the database
//-----------------------------------------------------------------------------
void CUserSession::SQLDBResponse(int cmdID, int returnState, int returnVal, void *dataBlock)
{
	// check to see if sesion is still valid
	if (!m_iUserID || !m_pDB)
		return;

	bool bHandled = false;
	int arraySize = ARRAYSIZE(g_DBMsgDispatch);
	for (int i = 0; i < arraySize; i++)
	{
		if (g_DBMsgDispatch[i].cmdID == cmdID && g_DBMsgDispatch[i].returnState == returnState)
		{
			// dispatch the function
			(this->*g_DBMsgDispatch[i].msgFunc)(returnVal, dataBlock);
			bHandled = true;
			break;
		}
	}

	if (!bHandled)
	{
		g_pConsole->Print(9, "**** Error: no handler for CUserSession::SQLDBResponse(%d, %d)\n", cmdID, returnState);
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CUserSession::DBMsg_Login(int returnVal, void *dataBlock)
{
	ITrackerUserDatabase::UserLogin_t *data = (ITrackerUserDatabase::UserLogin_t *)dataBlock;
	int loginState = returnVal;
	if (loginState > 0)
	{
		// successful login
		m_iUserSessionState = USERSESSION_ACTIVE;
		m_iStatus = data->acquiredStatus;

		// reply to the user with a login ok message
		ISendMessage *msg = CreateUserMessage(TSVC_LOGINOK);
		msg->WriteInt("status", m_iStatus);
		SendMessage(msg, NET_RELIABLE);

		g_pConsole->Print( 0, "Sending 'LoginOK' message to '%s'\n", m_NetAddress.ToStaticString() );

		PostLogin();
	}
	else
	{
		if (loginState == -3)
		{
			// get the old account and they will be told to log off
			g_pDataManager->TrackerUser(m_iUserID)->User_GetSessionInfo(this, STATE_DISCONNECTINGUSER, m_iUserID);
			m_iUserSessionState = USERSESSION_CONNECTING;
		}
		else
		{
			m_iUserSessionState = USERSESSION_CONNECTFAILED;
			sessionmanager()->FreeUserSession(this);
		}

		g_pConsole->Print(4, "User_Login(%d) failed: %d\n", m_iUserID, loginState);
		
		// send login failed message
		m_iStatus = 0;

		ISendMessage *reply = CreateUserMessage(TSVC_LOGINFAIL);
		reply->WriteInt("reason", loginState);
		SendMessage(reply, NET_RELIABLE);
	}
}

//-----------------------------------------------------------------------------
// Purpose: Called when the user has finished being logged off
//-----------------------------------------------------------------------------
void CUserSession::DBMsg_Logoff(int returnVal, void *dataBlock)
{
	// tell the friends that this user is going offline if we are successful
	if (returnVal > 0)
	{
		// logoff sucessful
		g_pConsole->Print(0, "Finished logging off user '%d'\n", m_iUserID);

		// tell everyone about their status
		UpdateStatusToFriends();

		// remove all watches, from all databases
		int dbCount = g_pDataManager->TrackerUserCount();
		for (int i = 0; i < dbCount; i++)
		{
			g_pDataManager->TrackerUserByIndex(i).db->User_RemoveWatcher(m_iUserID);
		}
	}
	else if (returnVal < 0)
	{
		g_pConsole->Print(0, "** Error '%d' logging off user '%d'\n", returnVal, m_iUserID);

		// kill the session
		sessionmanager()->FreeUserSession(this);
	}
	else
	{
		// returnVal is 0, which means that while the user was not logged off, it was still successful
		// user is probably logged into a different server with a dead connection left here

		// kill the session
		sessionmanager()->FreeUserSession(this);
	}
}


//-----------------------------------------------------------------------------
// Purpose: Used when we're trying to log in, but we're already logged in elsewhere.
//			disconnects our other connection from the server
//-----------------------------------------------------------------------------
void CUserSession::DBMsg_GetSessionInfo_DisconnectingUser(int returnVal, void *dataBlock)
{
	if (returnVal < 1)
		return;

	ITrackerUserDatabase::user_t *data = (ITrackerUserDatabase::user_t *)dataBlock;
	if (data->userStatus < 1)
		return;	// they're not online

	topology()->ForceDisconnectUser(data->userID, data->userSessionID, data->userServerID);

	// free this user account
	m_iUserSessionState = USERSESSION_CONNECTFAILED;
	sessionmanager()->FreeUserSession(this);
}

//-----------------------------------------------------------------------------
// Purpose: Tells the user that they should check their messages
//-----------------------------------------------------------------------------
void CUserSession::DBMsg_GetSessionInfo_CheckMessages(int returnVal, void *dataBlock)
{
	if (returnVal < 1)
		return;

	ITrackerUserDatabase::user_t *data = (ITrackerUserDatabase::user_t *)dataBlock;
	if (data->userStatus < 1)
		return;	// they're not online

	// tell them, check their messages
	topology()->UserCheckMessages(data->userID, data->userSessionID, data->userServerID);
}

//-----------------------------------------------------------------------------
// Purpose: Adds a new watcher to ourselves, someone we have probably just authed
//-----------------------------------------------------------------------------
void CUserSession::DBMsg_GetSessionInfo_AddWatch(int returnVal, void *dataBlock)
{
	if (returnVal < 1)
		return;

	ITrackerUserDatabase::user_t *data = (ITrackerUserDatabase::user_t *)dataBlock;

	if (data->userStatus < 1)
		return;	// they're not online, don't add the watch

	if (m_pDB)
	{
		m_pDB->User_AddSingleWatch(data->userID, data->userSessionID, data->userServerID, m_iUserID);
	}
}

//-----------------------------------------------------------------------------
// Purpose: Notify two users of each other's status
//-----------------------------------------------------------------------------
void CUserSession::DBMsg_GetSessionInfo_ExchangeStatus(int returnVal, void *dataBlock)
{
	if (returnVal < 1)
		return;

	// send our status to the friend
	DBMsg_GetSessionInfo_SendingStatus(returnVal, dataBlock);

	// send friend's status to us
	ITrackerUserDatabase::user_t *data = (ITrackerUserDatabase::user_t *)dataBlock;
	if (data->userStatus < 1)
		return;	// they're not online

	// tell the user our status
	ISendMessage *msg = CreateUserMessage(TSVC_FRIENDS);

	msg->WriteInt("count", 1);

	unsigned int msgBuf[6];
	int bytesWritten = ConstructFriendsStatusMessageData(data, 1, msgBuf);
	msg->WriteBlob("status", msgBuf, bytesWritten);

	SendMessage(msg, NET_RELIABLE);
}

//-----------------------------------------------------------------------------
// Purpose: Sends the status of a single friend
//-----------------------------------------------------------------------------
void CUserSession::DBMsg_GetSessionInfo_SendingStatus(int returnVal, void *dataBlock)
{
	if (returnVal < 1)
		return;

	ITrackerUserDatabase::user_t *data = (ITrackerUserDatabase::user_t *)dataBlock;
	if (data->userStatus < 1)
		return;	// they're not online

	// tell the user our status
	CUtlMsgBuffer msgBuffer;
	msgBuffer.WriteInt("_id", TSVC_FRIENDS);
	msgBuffer.WriteInt("count", 1);

	int msgBuf[6];
	int intsWritten = 0;
	msgBuf[intsWritten++] = m_iUserID;
	// write status second
	msgBuf[intsWritten++] = m_iStatus;
	// write session id third
	msgBuf[intsWritten++] = data->userSessionID;
	// write IP address
	msgBuf[intsWritten++] = m_NetAddress.IP();
	msgBuf[intsWritten++] = m_NetAddress.Port();

	if (m_iBuildNum >= COMPATILIBITY_SERVERID_SUPPORT_VERSION_MIN)
	{
		// write serverID
		msgBuf[intsWritten++] = topology()->GetServerID();
	}

⌨️ 快捷键说明

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