about summary refs log tree commit diff
path: root/src/engine/server/register.cpp
diff options
context:
space:
mode:
authorMagnus Auvinen <magnus.auvinen@gmail.com>2010-05-29 07:25:38 +0000
committerMagnus Auvinen <magnus.auvinen@gmail.com>2010-05-29 07:25:38 +0000
commit72c06a258940696093f255fb1061beb58e1cdd0b (patch)
tree36b9a7712eec2d4f07837eab9c38ef1c5af85319 /src/engine/server/register.cpp
parente56feb597bc743677633432f77513b02907fd169 (diff)
downloadzcatch-72c06a258940696093f255fb1061beb58e1cdd0b.tar.gz
zcatch-72c06a258940696093f255fb1061beb58e1cdd0b.zip
copied refactor to trunk
Diffstat (limited to 'src/engine/server/register.cpp')
-rw-r--r--src/engine/server/register.cpp264
1 files changed, 264 insertions, 0 deletions
diff --git a/src/engine/server/register.cpp b/src/engine/server/register.cpp
new file mode 100644
index 00000000..959b9288
--- /dev/null
+++ b/src/engine/server/register.cpp
@@ -0,0 +1,264 @@
+#include <base/system.h>
+#include <engine/shared/network.h>
+#include <engine/shared/config.h>
+#include <engine/shared/engine.h>
+#include <engine/masterserver.h>
+
+#include <mastersrv/mastersrv.h>
+
+#include "register.h"
+
+CRegister::CRegister()
+{
+	m_pNetServer = 0;
+	m_pMasterServer = 0;
+
+	m_RegisterState = REGISTERSTATE_START;
+	m_RegisterStateStart = 0;
+	m_RegisterFirst = 1;
+	m_RegisterCount = 0;
+
+	mem_zero(m_aMasterserverInfo, sizeof(m_aMasterserverInfo));
+	m_RegisterRegisteredServer = -1;
+}
+
+void CRegister::RegisterNewState(int State)
+{
+	m_RegisterState = State;
+	m_RegisterStateStart = time_get();
+}
+
+void CRegister::RegisterSendFwcheckresponse(NETADDR *pAddr)
+{
+	CNetChunk Packet;
+	Packet.m_ClientID = -1;
+	Packet.m_Address = *pAddr;
+	Packet.m_Flags = NETSENDFLAG_CONNLESS;
+	Packet.m_DataSize = sizeof(SERVERBROWSE_FWRESPONSE);
+	Packet.m_pData = SERVERBROWSE_FWRESPONSE;
+	m_pNetServer->Send(&Packet);
+}
+	
+void CRegister::RegisterSendHeartbeat(NETADDR Addr)
+{
+	static unsigned char aData[sizeof(SERVERBROWSE_HEARTBEAT) + 2];
+	unsigned short Port = g_Config.m_SvPort;
+	CNetChunk Packet;
+	
+	mem_copy(aData, SERVERBROWSE_HEARTBEAT, sizeof(SERVERBROWSE_HEARTBEAT));
+	
+	Packet.m_ClientID = -1;
+	Packet.m_Address = Addr;
+	Packet.m_Flags = NETSENDFLAG_CONNLESS;
+	Packet.m_DataSize = sizeof(SERVERBROWSE_HEARTBEAT) + 2;
+	Packet.m_pData = &aData;
+
+	// supply the set port that the master can use if it has problems
+	if(g_Config.m_SvExternalPort)
+		Port = g_Config.m_SvExternalPort;
+	aData[sizeof(SERVERBROWSE_HEARTBEAT)] = Port >> 8;
+	aData[sizeof(SERVERBROWSE_HEARTBEAT)+1] = Port&0xff;
+	m_pNetServer->Send(&Packet);
+}
+
+void CRegister::RegisterSendCountRequest(NETADDR Addr)
+{
+	CNetChunk Packet;
+	Packet.m_ClientID = -1;
+	Packet.m_Address = Addr;
+	Packet.m_Flags = NETSENDFLAG_CONNLESS;
+	Packet.m_DataSize = sizeof(SERVERBROWSE_GETCOUNT);
+	Packet.m_pData = SERVERBROWSE_GETCOUNT;
+	m_pNetServer->Send(&Packet);
+}
+
+void CRegister::RegisterGotCount(CNetChunk *pChunk)
+{
+	unsigned char *pData = (unsigned char *)pChunk->m_pData;
+	int Count = (pData[sizeof(SERVERBROWSE_COUNT)]<<8) | pData[sizeof(SERVERBROWSE_COUNT)+1];
+
+	for(int i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++)
+	{
+		if(net_addr_comp(&m_aMasterserverInfo[i].m_Addr, &pChunk->m_Address) == 0)
+		{
+			m_aMasterserverInfo[i].m_Count = Count;
+			break;
+		}
+	}
+}
+
+void CRegister::Init(CNetServer *pNetServer, IEngineMasterServer *pMasterServer)
+{
+	m_pNetServer = pNetServer;
+	m_pMasterServer = pMasterServer;
+}
+
+void CRegister::RegisterUpdate()
+{
+	int64 Now = time_get();
+	int64 Freq = time_freq();
+
+	if(!g_Config.m_SvRegister)
+		return;
+
+	m_pMasterServer->Update();
+
+	if(m_RegisterState == REGISTERSTATE_START)
+	{
+		m_RegisterCount = 0;
+		m_RegisterFirst = 1;
+		RegisterNewState(REGISTERSTATE_UPDATE_ADDRS);
+		m_pMasterServer->RefreshAddresses();
+		dbg_msg("register", "refreshing ip addresses");
+	}
+	else if(m_RegisterState == REGISTERSTATE_UPDATE_ADDRS)
+	{
+		m_RegisterRegisteredServer = -1;
+	
+		if(!m_pMasterServer->IsRefreshing())
+		{
+			int i;
+			for(i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++)
+			{
+				NETADDR addr = m_pMasterServer->GetAddr(i);
+				m_aMasterserverInfo[i].m_Addr = addr;
+				m_aMasterserverInfo[i].m_Count = 0;
+			
+				if(!addr.ip[0] && !addr.ip[1] && !addr.ip[2] && !addr.ip[3])
+					m_aMasterserverInfo[i].m_Valid = 0;
+				else
+				{
+					m_aMasterserverInfo[i].m_Valid = 1;
+					m_aMasterserverInfo[i].m_Count = -1;
+					m_aMasterserverInfo[i].m_LastSend = 0;
+				}
+			}
+			
+			dbg_msg("register", "fetching server counts");
+			RegisterNewState(REGISTERSTATE_QUERY_COUNT);
+		}
+	}
+	else if(m_RegisterState == REGISTERSTATE_QUERY_COUNT)
+	{
+		int Left = 0;
+		for(int i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++)
+		{
+			if(!m_aMasterserverInfo[i].m_Valid)
+				continue;
+				
+			if(m_aMasterserverInfo[i].m_Count == -1)
+			{
+				Left++;
+				if(m_aMasterserverInfo[i].m_LastSend+Freq < Now)
+				{
+					m_aMasterserverInfo[i].m_LastSend = Now;
+					RegisterSendCountRequest(m_aMasterserverInfo[i].m_Addr);
+				}
+			}
+		}
+		
+		// check if we are done or timed out
+		if(Left == 0 || Now > m_RegisterStateStart+Freq*3)
+		{
+			// choose server
+			int Best = -1;
+			int i;
+			for(i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++)
+			{
+				if(!m_aMasterserverInfo[i].m_Valid || m_aMasterserverInfo[i].m_Count == -1)
+					continue;
+					
+				if(Best == -1 || m_aMasterserverInfo[i].m_Count < m_aMasterserverInfo[Best].m_Count)
+					Best = i;
+			}
+
+			// server chosen
+			m_RegisterRegisteredServer = Best;
+			if(m_RegisterRegisteredServer == -1)
+			{
+				dbg_msg("register", "WARNING: No master servers. Retrying in 60 seconds");
+				RegisterNewState(REGISTERSTATE_ERROR);
+			}
+			else
+			{			
+				dbg_msg("register", "choosen '%s' as master, sending heartbeats", m_pMasterServer->GetName(m_RegisterRegisteredServer));
+				m_aMasterserverInfo[m_RegisterRegisteredServer].m_LastSend = 0;
+				RegisterNewState(REGISTERSTATE_HEARTBEAT);
+			}
+		}
+	}
+	else if(m_RegisterState == REGISTERSTATE_HEARTBEAT)
+	{
+		// check if we should send heartbeat
+		if(Now > m_aMasterserverInfo[m_RegisterRegisteredServer].m_LastSend+Freq*15)
+		{
+			m_aMasterserverInfo[m_RegisterRegisteredServer].m_LastSend = Now;
+			RegisterSendHeartbeat(m_aMasterserverInfo[m_RegisterRegisteredServer].m_Addr);
+		}
+		
+		if(Now > m_RegisterStateStart+Freq*60)
+		{
+			dbg_msg("register", "WARNING: Master server is not responding, switching master");
+			RegisterNewState(REGISTERSTATE_START);
+		}
+	}
+	else if(m_RegisterState == REGISTERSTATE_REGISTERED)
+	{
+		if(m_RegisterFirst)
+			dbg_msg("register", "server registered");
+			
+		m_RegisterFirst = 0;
+		
+		// check if we should send new heartbeat again
+		if(Now > m_RegisterStateStart+Freq)
+		{
+			if(m_RegisterCount == 120) // redo the whole process after 60 minutes to balance out the master servers
+				RegisterNewState(REGISTERSTATE_START);
+			else
+			{
+				m_RegisterCount++;
+				RegisterNewState(REGISTERSTATE_HEARTBEAT);
+			}
+		}
+	}
+	else if(m_RegisterState == REGISTERSTATE_ERROR)
+	{
+		// check for restart
+		if(Now > m_RegisterStateStart+Freq*60)
+			RegisterNewState(REGISTERSTATE_START);
+	}
+}
+
+int CRegister::RegisterProcessPacket(CNetChunk *pPacket)
+{
+	if(pPacket->m_DataSize == sizeof(SERVERBROWSE_FWCHECK) &&
+		mem_comp(pPacket->m_pData, SERVERBROWSE_FWCHECK, sizeof(SERVERBROWSE_FWCHECK)) == 0)
+	{
+		RegisterSendFwcheckresponse(&pPacket->m_Address);
+		return 1;
+	}
+	else if(pPacket->m_DataSize == sizeof(SERVERBROWSE_FWOK) &&
+		mem_comp(pPacket->m_pData, SERVERBROWSE_FWOK, sizeof(SERVERBROWSE_FWOK)) == 0)
+	{
+		if(m_RegisterFirst)
+			dbg_msg("register", "no firewall/nat problems detected");
+		RegisterNewState(REGISTERSTATE_REGISTERED);
+		return 1;
+	}
+	else if(pPacket->m_DataSize == sizeof(SERVERBROWSE_FWERROR) &&
+		mem_comp(pPacket->m_pData, SERVERBROWSE_FWERROR, sizeof(SERVERBROWSE_FWERROR)) == 0)
+	{
+		dbg_msg("register", "ERROR: the master server reports that clients can not connect to this server.");
+		dbg_msg("register", "ERROR: configure your firewall/nat to let through udp on port %d.", g_Config.m_SvPort);
+		RegisterNewState(REGISTERSTATE_ERROR);
+		return 1;
+	}
+	else if(pPacket->m_DataSize == sizeof(SERVERBROWSE_COUNT)+2 &&
+		mem_comp(pPacket->m_pData, SERVERBROWSE_COUNT, sizeof(SERVERBROWSE_COUNT)) == 0)
+	{
+		RegisterGotCount(pPacket);
+		return 1;
+	}
+
+	return 0;
+}