📄 sessionmanager.cpp
字号:
//-----------------------------------------------------------------------------
// Purpose: Callback for receiving data blocks from the network
//-----------------------------------------------------------------------------
bool CSessionManager::ReceivedData(IReceiveMessage *dataBlock)
{
if (m_bLockedDown)
{
// don't accept any more messages when locked down
return true;
}
// if it's a login message, allocate a new session
switch (dataBlock->GetMsgID())
{
case TCLS_LOGIN:
{
// if it's a login message, allocate a new session
LoginNewUser(dataBlock);
return true;
}
case TCLS_CREATEUSER:
{
CreateNewUser(dataBlock);
return true;
}
case TCLS_VALIDATEUSER:
{
ValidateUser(dataBlock);
return true;
}
case TCLS_PING:
{
AcknowledgeUserPing(dataBlock);
return true;
}
default:
{
// try and match the message with an existing session
DispatchMessageToUserSession(dataBlock);
break;
}
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose: We have had a network message to a user fail, force them off
//-----------------------------------------------------------------------------
void CSessionManager::OnFailedMessage(IReceiveMessage *failedMsg)
{
// try and find the user
unsigned int sessionID = failedMsg->SessionID();
unsigned short sessionIndex = SESSION_INDEX(sessionID);
if (sessionIndex >= m_UserSessions.Size())
{
// bad packet, throw away
return;
}
if (m_UserSessions[sessionIndex].State() == USERSESSION_ACTIVE && m_UserSessions[sessionIndex].Status())
{
// they failed a general message, either a firewall issue or the user has crashed
m_UserSessions[sessionIndex].OnFailedMessage(failedMsg);
}
else if (m_UserSessions[sessionIndex].State() == USERSESSION_CONNECTING)
{
// challenge message failed, disconnect user
FreeUserSession(&m_UserSessions[sessionIndex]);
}
}
//-----------------------------------------------------------------------------
// Purpose: Flushes all logged in users out of the database
//-----------------------------------------------------------------------------
void CSessionManager::FlushUsers(bool force)
{
if (force)
{
// issue general flush of any user logged on to this machine
for (int i = 0; i < g_pDataManager->TrackerUserCount(); i++)
{
g_pDataManager->TrackerUserByIndex(i).db->Users_Flush();
}
}
else
{
// log out all users
for (int i = 0; i < m_UserSessions.Size(); i++)
{
if (m_UserSessions[i].State() == USERSESSION_ACTIVE)
{
m_UserSessions[i].Logoff(true, false, false);
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Attempts to log a user onto the server
// Input : *loginMsg - network message
//-----------------------------------------------------------------------------
void CSessionManager::LoginNewUser(IReceiveMessage *loginMsg)
{
// get the userID
unsigned int userID;
loginMsg->ReadUInt("uid", userID);
if (userID >= m_iLockedUserLowerRange && userID <= m_iLockedUserUpperRange)
{
// we can't log the user in since they're in the locked range - tell them to stay disconnected
g_pConsole->Print(6, "Locked range, sending disconnected message to %d\n", userID);
ISendMessage *msg = net()->CreateReply(TSVC_DISCONNECT, loginMsg);
msg->WriteInt("minTime", 1);
msg->WriteInt("maxTime", 4);
net()->SendMessage(msg, NET_RELIABLE);
}
else
{
// allocate a new user session
CUserSession *session = GetNewUserSession();
if (session->ReceivedMsg_Login(loginMsg))
{
// user login success; map in their user id
MapUserIDToUserSession(session->UID(), session);
}
else
{
// bad login attempt, clear user session
FreeUserSession(session);
}
}
}
//-----------------------------------------------------------------------------
// Purpose: inserts a mapping of userID -> CUserSession
//-----------------------------------------------------------------------------
void CSessionManager::MapUserIDToUserSession(unsigned int userID, CUserSession *userSession)
{
SessionMapItem_t searchItem = { userID, userSession };
m_IDMap.Insert(searchItem);
}
//-----------------------------------------------------------------------------
// Purpose: removes a userID -> CUserSession mapping
//-----------------------------------------------------------------------------
void CSessionManager::UnmapUserID(unsigned int userID)
{
SessionMapItem_t searchItem = { userID, NULL };
int index = m_IDMap.Find(searchItem);
if (m_IDMap.IsValidIndex(index))
{
m_IDMap.RemoveAt(index);
}
}
//-----------------------------------------------------------------------------
// Purpose: Tries to create a new user
// Does not log them on
//-----------------------------------------------------------------------------
void CSessionManager::CreateNewUser(IReceiveMessage *msg)
{
// temporarily store the new new user
int newIndex = m_CreateUsers.AddToTail();
CreateUser_t &user = m_CreateUsers[newIndex];
msg->ReadString("username", user.userName, 32);
msg->ReadString("firstname", user.firstName, 32);
msg->ReadString("lastname", user.lastName, 32);
msg->ReadString("email", user.email, 128);
msg->ReadString("password", user.password, 32);
// make sure the user doesn't exist on any of the servers
user.resultsNeeded = g_pDataManager->TrackerUserCount();
user.failed = false;
user.ip = msg->NetAddress().IP();
user.port = msg->NetAddress().Port();
user.requestTime = GetCurrentTime();
// ask all the servers whether they've seen this user
for (int i = 0; i < g_pDataManager->TrackerUserCount(); i++)
{
ITrackerDatabaseManager::db_t &db = g_pDataManager->TrackerUserByIndex(i);
db.db->User_Validate(this, user.email, user.password, user.ip, user.port, newIndex);
}
}
//-----------------------------------------------------------------------------
// Purpose: Checks to see if the specified user exists, and replies to the message
// with the users userID
// Input : *validateMsg -
//-----------------------------------------------------------------------------
void CSessionManager::ValidateUser(IReceiveMessage *msg)
{
char email[128];
char password[32];
// parse out the createUserMsg
msg->ReadString("email", email, 128);
msg->ReadString("password", password, 32);
// check to see if the user exists on any server
for (int i = 0; i < g_pDataManager->TrackerUserCount(); i++)
{
g_pDataManager->TrackerUserByIndex(i).db->User_Validate(this, email, password, msg->NetAddress().IP(), msg->NetAddress().Port(), (unsigned int)~0);
}
}
//-----------------------------------------------------------------------------
// Purpose: Handles a simple ping message from a user, and replies with an 'Ack'
//-----------------------------------------------------------------------------
void CSessionManager::AcknowledgeUserPing(IReceiveMessage *pingMsg)
{
ISendMessage *ackMsg = net()->CreateReply(TSVC_PINGACK, pingMsg);
net()->SendMessage(ackMsg, NET_UNRELIABLE);
}
//-----------------------------------------------------------------------------
// Purpose: Returns the current time, in seconds
//-----------------------------------------------------------------------------
float CSessionManager::GetCurrentTime()
{
//!! need to use a higher res timer
static long timeBase = 0;
time_t timer;
::time(&timer);
// hack: normalize the timebase so the float isn't so inaccurate
if (!timeBase)
{
timeBase = (long)timer;
}
return (float)((long)timer - timeBase);
}
//-----------------------------------------------------------------------------
// Purpose: causes the main thread to sleep until it's signalled
//-----------------------------------------------------------------------------
void CSessionManager::WaitForEvent(unsigned long timeoutMillis)
{
Event_WaitForEvent(m_hEvent, timeoutMillis);
}
//-----------------------------------------------------------------------------
// Purpose: returns the sleep event
//-----------------------------------------------------------------------------
unsigned long CSessionManager::GetWindowsEvent()
{
return m_hEvent;
}
//-----------------------------------------------------------------------------
// Purpose: Wakes up the main thread
//-----------------------------------------------------------------------------
void CSessionManager::WakeUp()
{
Event_SignalEvent(m_hEvent);
}
//-----------------------------------------------------------------------------
// Purpose: handles a response from the sql database
//-----------------------------------------------------------------------------
void CSessionManager::SQLDBResponse(int cmdID, int returnState, int returnVal, void *data)
{
if (cmdID == CMD_VALIDATE)
{
// response to the Validate command is in
ITrackerUserDatabase::UserValidate_t *response = (ITrackerUserDatabase::UserValidate_t *)data;
if (response->temporaryID == -1)
{
// reply with the returned state
ISendMessage *reply = net()->CreateMessage(TSVC_USERVALID);
CNetAddress addr;
addr.SetIP(response->IP);
addr.SetPort(response->Port);
reply->SetNetAddress(addr);
reply->SetEncrypted(true);
unsigned int userID = *((unsigned int *)(&returnVal));
reply->WriteUInt("userID", userID);
net()->SendMessage(reply, NET_RELIABLE);
}
else
{
// user is attempting to be created
if (!m_CreateUsers.IsValidIndex(response->temporaryID))
return;
CreateUser_t &user = m_CreateUsers[response->temporaryID];
if (returnVal != -1)
{
// user already exists; send back a fail message
user.failed = true;
// bad ID, write out an error string
ISendMessage *reply = net()->CreateMessage(TSVC_USERCREATED);
CNetAddress addr;
addr.SetIP(user.ip);
addr.SetPort(user.port);
reply->SetNetAddress(addr);
reply->SetEncrypted(true);
char *msg = "Could not create new account.\nUser with that email address already exists.";
reply->WriteString("error", msg);
net()->SendMessage(reply, NET_RELIABLE);
}
// check to see if we've received a response from each DB
user.resultsNeeded--;
if (user.resultsNeeded == 0)
{
if (!user.failed)
{
// user is ok, reserve a userID for them
g_pDataManager->TrackerDistro()->ReserveUserID(this, user.email, user.password, user.userName, user.firstName, user.lastName, user.ip, user.port);
}
// remove the user
m_CreateUsers.Remove(response->temporaryID);
}
}
}
else if (cmdID == CMD_RESERVEUSERID)
{
// we've got a userID back
ITrackerDistroDatabase::ReserveUserID_t *user = (ITrackerDistroDatabase::ReserveUserID_t *)data;
int userID = returnVal;
if (userID < 1)
{
// send back an error message
ISendMessage *reply = net()->CreateMessage(TSVC_USERCREATED);
CNetAddress addr;
addr.SetIP(user->ip);
addr.SetPort(user->port);
reply->SetNetAddress(addr);
reply->SetEncrypted(true);
reply->WriteUInt("newUID", userID);
if (returnVal == -1)
{
// bad ID, write out an error string
char *msg = "Could not create new account.\nUser with that email address already exists.";
reply->WriteString("error", msg);
}
else if (returnVal < 1)
{
char *msg = "Server could not create user.\nPlease try again at another time.";
reply->WriteString("error", msg);
}
net()->SendMessage(reply, NET_RELIABLE);
return; // don't continue
}
// success, create the user entry in the database in the reserved slot
g_pDataManager->TrackerUser(userID)->User_Create(this, userID, user->email, user->password, user->username, user->firstname, user->lastname, user->ip, user->port);
}
else if (cmdID == CMD_CREATE)
{
ITrackerUserDatabase::UserCreate_t *response = (ITrackerUserDatabase::UserCreate_t *)data;
// build and reply with a create user success message
ISendMessage *reply = net()->CreateMessage(TSVC_USERCREATED);
CNetAddress addr;
addr.SetIP(response->IP);
addr.SetPort(response->Port);
reply->SetNetAddress(addr);
reply->SetEncrypted(true);
unsigned int newUID = returnVal;
reply->WriteUInt("newUID", newUID);
if (returnVal < 1)
{
char *msg = "Server could not create user.\nPlease try again at another time.";
reply->WriteString("error", msg);
}
net()->SendMessage(reply, NET_RELIABLE);
g_pConsole->Print( 1, "Sending UserCreated(%d) message to '%s'\n", returnVal, reply->NetAddress().ToStaticString() );
}
}
//-----------------------------------------------------------------------------
// Purpose: Returns number of active users on server
//-----------------------------------------------------------------------------
int CSessionManager::ActiveUserCount()
{
return m_IDMap.Count();
}
//-----------------------------------------------------------------------------
// Purpose: Returns maximum number of users holdable
//-----------------------------------------------------------------------------
int CSessionManager::MaxUserCount()
{
return m_UserSessions.Size();
}
//-----------------------------------------------------------------------------
// Purpose: Displays current list of users on the server
//-----------------------------------------------------------------------------
void CSessionManager::PrintUserList()
{
g_pConsole->Print(9, "UID\tSTATUS\tUSERNAME\t\t\tIP ADDRESS\n");
for (int i = 0; i < m_UserSessions.Size(); i++)
{
CUserSession &session = m_UserSessions[i];
if (session.State() == USERSESSION_ACTIVE)
{
CNetAddress addr;
addr.SetIP(session.IP());
addr.SetPort(session.Port());
g_pConsole->Print(9, "%d\t%d\t%s\t\t\t%s\n", session.UID(), session.Status(), session.UserName(), addr.ToStaticString());
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -