Merge pull request #301 from east/session_rejoin

Make rejoining session possible before timeout protection triggers
This commit is contained in:
east 2015-08-23 18:18:04 +02:00
commit 22860fbaa7
5 changed files with 89 additions and 18 deletions

View file

@ -760,16 +760,13 @@ void CServer::DoSnapshot()
GameServer()->OnPostSnap();
}
int CServer::NewClientNoAuthCallback(int ClientID, void *pUser)
int CServer::ClientRejoinCallback(int ClientID, void *pUser)
{
CServer *pThis = (CServer *)pUser;
pThis->m_aClients[ClientID].m_State = CClient::STATE_CONNECTING;
pThis->m_aClients[ClientID].m_aName[0] = 0;
pThis->m_aClients[ClientID].m_aClan[0] = 0;
pThis->m_aClients[ClientID].m_Country = -1;
pThis->m_aClients[ClientID].m_Authed = AUTHED_NO;
pThis->m_aClients[ClientID].m_AuthTries = 0;
pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
pThis->m_aClients[ClientID].Reset();
pThis->SendMap(ClientID);
@ -777,6 +774,26 @@ int CServer::NewClientNoAuthCallback(int ClientID, void *pUser)
return 0;
}
int CServer::NewClientNoAuthCallback(int ClientID, bool Reset, void *pUser)
{
CServer *pThis = (CServer *)pUser;
if (Reset)
{
pThis->m_aClients[ClientID].m_State = CClient::STATE_CONNECTING;
pThis->m_aClients[ClientID].m_aName[0] = 0;
pThis->m_aClients[ClientID].m_aClan[0] = 0;
pThis->m_aClients[ClientID].m_Country = -1;
pThis->m_aClients[ClientID].m_Authed = AUTHED_NO;
pThis->m_aClients[ClientID].m_AuthTries = 0;
pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
pThis->m_aClients[ClientID].Reset();
}
pThis->SendMap(ClientID);
return 0;
}
int CServer::NewClientCallback(int ClientID, void *pUser)
{
CServer *pThis = (CServer *)pUser;
@ -1028,8 +1045,9 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf);
m_aClients[ClientID].m_State = CClient::STATE_READY;
GameServer()->OnClientConnected(ClientID);
SendConnectionReady(ClientID);
}
SendConnectionReady(ClientID);
}
else if(Msg == NETMSG_ENTERGAME)
{
@ -1555,7 +1573,7 @@ int CServer::Run()
return -1;
}
m_NetServer.SetCallbacks(NewClientCallback, NewClientNoAuthCallback, DelClientCallback, this);
m_NetServer.SetCallbacks(NewClientCallback, NewClientNoAuthCallback, ClientRejoinCallback, DelClientCallback, this);
m_Econ.Init(Console(), &m_ServerBan);

View file

@ -220,9 +220,11 @@ public:
void DoSnapshot();
static int NewClientCallback(int ClientID, void *pUser);
static int NewClientNoAuthCallback(int ClientID, void *pUser);
static int NewClientNoAuthCallback(int ClientID, bool Reset, void *pUser);
static int DelClientCallback(int ClientID, const char *pReason, void *pUser);
static int ClientRejoinCallback(int ClientID, void *pUser);
void SendMap(int ClientID);
void SendConnectionReady(int ClientID);
void SendRconLine(int ClientID, const char *pLine);

View file

@ -96,7 +96,8 @@ enum
typedef int (*NETFUNC_DELCLIENT)(int ClientID, const char* pReason, void *pUser);
typedef int (*NETFUNC_NEWCLIENT)(int ClientID, void *pUser);
typedef int (*NETFUNC_NEWCLIENT_NOAUTH)(int ClientID, void *pUser);
typedef int (*NETFUNC_NEWCLIENT_NOAUTH)(int ClientID, bool Reset, void *pUser);
typedef int (*NETFUNC_CLIENTREJOIN)(int ClientID, void *pUser);
struct CNetChunk
{
@ -190,7 +191,7 @@ public:
bool m_TimeoutProtected;
bool m_TimeoutSituation;
void Reset();
void Reset(bool Rejoin=false);
void Init(NETSOCKET Socket, bool BlockCloseMsg);
int Connect(NETADDR *pAddr);
void Disconnect(const char *pReason);
@ -290,6 +291,7 @@ class CNetServer
NETFUNC_NEWCLIENT m_pfnNewClient;
NETFUNC_NEWCLIENT_NOAUTH m_pfnNewClientNoAuth;
NETFUNC_DELCLIENT m_pfnDelClient;
NETFUNC_CLIENTREJOIN m_pfnClientRejoin;
void *m_UserPtr;
@ -301,6 +303,7 @@ class CNetServer
void OnTokenCtrlMsg(NETADDR &Addr, int ControlMsg, const CNetPacketConstruct &Packet);
void OnPreConnMsg(NETADDR &Addr, CNetPacketConstruct &Packet);
void OnConnCtrlMsg(NETADDR &Addr, int ClientID, int ControlMsg, const CNetPacketConstruct &Packet);
bool ClientExists(const NETADDR &Addr) { return GetClientSlot(Addr) != -1; };
int GetClientSlot(const NETADDR &Addr);
void SendControl(NETADDR &Addr, int ControlMsg, const void *pExtra, int ExtraSize, SECURITY_TOKEN SecurityToken);
@ -311,7 +314,7 @@ class CNetServer
public:
int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_NEWCLIENT_NOAUTH pfnNewClientNoAuth, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_NEWCLIENT_NOAUTH pfnNewClientNoAuth, NETFUNC_CLIENTREJOIN pfnClientRejoin, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
//
bool Open(NETADDR BindAddr, class CNetBan *pNetBan, int MaxClients, int MaxClientsPerIP, int Flags);

View file

@ -16,7 +16,7 @@ void CNetConnection::ResetStats()
m_LastUpdateTime = 0;
}
void CNetConnection::Reset()
void CNetConnection::Reset(bool Rejoin)
{
m_Sequence = 0;
m_Ack = 0;
@ -24,12 +24,17 @@ void CNetConnection::Reset()
m_TimeoutProtected = false;
m_TimeoutSituation = false;
m_State = NET_CONNSTATE_OFFLINE;
if (!Rejoin)
{
m_State = NET_CONNSTATE_OFFLINE;
m_Token = -1;
m_SecurityToken = NET_SECURITY_TOKEN_UNKNOWN;
}
m_LastSendTime = 0;
m_LastRecvTime = 0;
//m_LastUpdateTime = 0;
m_Token = -1;
m_SecurityToken = NET_SECURITY_TOKEN_UNKNOWN;
//mem_zero(&m_PeerAddr, sizeof(m_PeerAddr));
m_UnknownSeq = false;

View file

@ -60,10 +60,11 @@ int CNetServer::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT p
return 0;
}
int CNetServer::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_NEWCLIENT_NOAUTH pfnNewClientNoAuth, NETFUNC_DELCLIENT pfnDelClient, void *pUser)
int CNetServer::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_NEWCLIENT_NOAUTH pfnNewClientNoAuth, NETFUNC_CLIENTREJOIN pfnClientRejoin, NETFUNC_DELCLIENT pfnDelClient, void *pUser)
{
m_pfnNewClient = pfnNewClient;
m_pfnNewClientNoAuth = pfnNewClientNoAuth;
m_pfnClientRejoin = pfnClientRejoin;
m_pfnDelClient = pfnDelClient;
m_UserPtr = pUser;
return 0;
@ -207,7 +208,7 @@ int CNetServer::TryAcceptClient(NETADDR &Addr, SECURITY_TOKEN SecurityToken, boo
if (VanillaAuth)
m_pfnNewClientNoAuth(Slot, m_UserPtr);
m_pfnNewClientNoAuth(Slot, true, m_UserPtr);
else
m_pfnNewClient(Slot, m_UserPtr);
@ -359,6 +360,43 @@ void CNetServer::OnPreConnMsg(NETADDR &Addr, CNetPacketConstruct &Packet)
}
}
void CNetServer::OnConnCtrlMsg(NETADDR &Addr, int ClientID, int ControlMsg, const CNetPacketConstruct &Packet)
{
if (ControlMsg == NET_CTRLMSG_CONNECT)
{
// got connection attempt inside of valid session
// the client probably wants to reconnect
bool SupportsToken = Packet.m_DataSize >=
(int)(1 + sizeof(SECURITY_TOKEN_MAGIC) + sizeof(SECURITY_TOKEN)) &&
!mem_comp(&Packet.m_aChunkData[1], SECURITY_TOKEN_MAGIC, sizeof(SECURITY_TOKEN_MAGIC));
if (SupportsToken)
{
// response connection request with token
SECURITY_TOKEN Token = GetToken(Addr);
SendControl(Addr, NET_CTRLMSG_CONNECTACCEPT, SECURITY_TOKEN_MAGIC, sizeof(SECURITY_TOKEN_MAGIC), Token);
}
if (g_Config.m_Debug)
dbg_msg("security", "client %d wants to reconnect", ClientID);
}
else if (ControlMsg == NET_CTRLMSG_ACCEPT && Packet.m_DataSize == 1 + sizeof(SECURITY_TOKEN))
{
SECURITY_TOKEN Token = ToSecurityToken(&Packet.m_aChunkData[1]);
if (Token == GetToken(Addr))
{
// correct token
// try to accept client
if (g_Config.m_Debug)
dbg_msg("security", "client %d reconnect");
// reset netconn and process rejoin
m_aSlots[ClientID].m_Connection.Reset(true);
m_pfnClientRejoin(ClientID, m_UserPtr);
}
}
}
void CNetServer::OnTokenCtrlMsg(NETADDR &Addr, int ControlMsg, const CNetPacketConstruct &Packet)
{
if (ClientExists(Addr))
@ -471,6 +509,11 @@ int CNetServer::Recv(CNetChunk *pChunk)
if (Slot != -1)
{
// found
// control
if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONTROL)
OnConnCtrlMsg(Addr, Slot, m_RecvUnpacker.m_Data.m_aChunkData[0], m_RecvUnpacker.m_Data);
if(m_aSlots[Slot].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr))
{
if(m_RecvUnpacker.m_Data.m_DataSize)