📄 usersession.cpp
字号:
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 + -