refactored mastersrv, working for 0.7 only currently

This commit is contained in:
heinrich5991 2012-07-27 15:51:31 +02:00 committed by oy
parent e49e67e2f4
commit 1c591793b0
6 changed files with 901 additions and 10 deletions

View file

@ -60,7 +60,7 @@ enum
NET_SEEDTIME = 10,
NET_MAX_PACKETSIZE = 1400,
NET_MAX_PAYLOAD = NET_MAX_PACKETSIZE-6,
NET_MAX_PAYLOAD = NET_MAX_PACKETSIZE-15,
NET_MAX_CHUNKHEADERSIZE = 3,
NET_PACKETHEADERSIZE = 11,
NET_PACKETHEADERSIZE_LEGACY = 3,

View file

@ -13,8 +13,623 @@
#include "mastersrv.h"
int main(int argc, const char **argv) // ignore_convention
{
dbg_logger_stdout();
net_init();
enum {
IKernel *pKernel = IKernel::Create();
IStorage *pStorage = CreateStorage("Teeworlds", IStorage::STORAGETYPE_BASIC, argc, argv);
IConfig *pConfig = CreateConfig();
IConsole *pConsole = CreateConsole(CFGFLAG_MASTER);
IMastersrv *pMastersrv = CreateMastersrv();
bool RegisterFail = !pKernel->RegisterInterface(pStorage);
RegisterFail |= !pKernel->RegisterInterface(pConsole);
RegisterFail |= !pKernel->RegisterInterface(pConfig);
RegisterFail |= !pKernel->RegisterInterface(pMastersrv);
if(RegisterFail)
return -1;
pConfig->Init();
if(argc > 1) // ignore_convention
pConsole->ParseArguments(argc-1, &argv[1]); // ignore_convention
int Result;
if((Result = pMastersrv->Init()) != 0)
{
dbg_msg("mastersrv", "initialisation failed (%d)", Result);
return Result;
}
Result = pMastersrv->Run();
delete pMastersrv;
delete pConsole;
delete pConfig;
delete pStorage;
delete pKernel;
return Result;
}
void IMastersrvSlave::NetaddrToMastersrv(CMastersrvAddr *pOut, const NETADDR *pIn)
{
dbg_assert(pIn->type == NETTYPE_IPV6 || pIn->type == NETTYPE_IPV4, "nettype not supported");
if(pIn->type == NETTYPE_IPV6)
{
mem_copy(pOut->m_aIp, pIn->ip, sizeof(pOut->m_aIp));
}
else if(pIn->type == NETTYPE_IPV4)
{
static const char aIPV4Mapping[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
mem_copy(pOut->m_aIp, aIPV4Mapping, sizeof(aIPV4Mapping));
mem_copy(pOut->m_aIp + 12, pIn->ip, 4);
}
pOut->m_aPort[0] = (pIn->port>>8)&0xff;
pOut->m_aPort[1] = (pIn->port>>0)&0xff;
}
class CMastersrv : public IMastersrv
{
public:
enum
{
MAX_SERVERS=1200,
MAX_CHECKSERVERS=MAX_SERVERS,
MAX_PACKETS=16,
EXPIRE_TIME=90,
BAN_REFRESH_TIME=300,
PACKET_REFRESH_TIME=5,
};
CMastersrv();
~CMastersrv();
virtual int Init();
virtual int Run();
virtual void AddServer(const NETADDR *pAddr, void *pUserData, int Version);
virtual void AddCheckserver(const NETADDR *pAddr, const NETADDR *pAltAddr, void *pUserData, int Version);
virtual void SendList(const NETADDR *pAddr, void *pUserData, int Version);
virtual int GetCount() const;
virtual int Send(int Socket, const CNetChunk *pPacket, TOKEN PacketToken, int PacketVersion);
void PurgeServers();
void UpdateServers();
void BuildPackets();
void ReloadBans();
private:
IConsole *m_pConsole;
CNetBan m_NetBan;
CNetClient m_NetOp;
CNetClient m_NetChecker;
int64 m_BanRefreshTime;
int64 m_PacketRefreshTime;
struct CServerEntry
{
NETADDR m_Address;
void *m_pSlaveUserData;
int m_Version;
int64 m_Expire;
};
struct CCheckServer
{
NETADDR m_Address;
NETADDR m_AltAddress;
void *m_pSlaveUserData;
int m_TryCount;
int64 m_TryTime;
int m_Version;
};
CServerEntry m_aServers[MAX_SERVERS];
int m_NumServers;
CCheckServer m_aCheckServers[MAX_CHECKSERVERS];
int m_NumCheckServers;
struct CMastersrvSlave
{
struct CPacket
{
char m_aData[NET_MAX_PAYLOAD];
int m_Size;
} m_aPackets[MAX_PACKETS];
int m_NumPackets;
IMastersrvSlave *m_pSlave;
};
CMastersrvSlave m_aSlaves[NUM_MASTERSRV];
};
IMastersrv *CreateMastersrv()
{
return new CMastersrv();
}
CMastersrv::CMastersrv()
{
for(int s = 0; s < NUM_MASTERSRV; s++)
m_aSlaves[s].m_pSlave = 0;
}
CMastersrv::~CMastersrv()
{
for(int s = 0; s < NUM_MASTERSRV; s++)
if(m_aSlaves[s].m_pSlave)
delete m_aSlaves[s].m_pSlave;
}
int CMastersrv::Init()
{
m_pConsole = Kernel()->RequestInterface<IConsole>();
m_NetBan.Init(m_pConsole, Kernel()->RequestInterface<IStorage>());
NETADDR BindAddr;
if(g_Config.m_Bindaddr[0] && net_host_lookup(g_Config.m_Bindaddr, &BindAddr, NETTYPE_ALL) == 0)
{
// got bindaddr
BindAddr.type = NETTYPE_ALL;
BindAddr.port = MASTERSERVER_PORT;
}
else
{
mem_zero(&BindAddr, sizeof(BindAddr));
BindAddr.type = NETTYPE_ALL;
BindAddr.port = MASTERSERVER_PORT;
}
if(!m_NetOp.Open(BindAddr, NETFLAG_ALLOWSTATELESS))
{
dbg_msg("mastersrv", "couldn't start network (op)");
return -1;
}
BindAddr.port = MASTERSERVER_PORT+1;
if(!m_NetChecker.Open(BindAddr, NETFLAG_ALLOWSTATELESS))
{
dbg_msg("mastersrv", "couldn't start network (checker)");
return -1;
}
// process pending commands
m_pConsole->StoreCommands(false);
for(int s = 0; s < NUM_MASTERSRV; s++)
m_aSlaves[s].m_NumPackets = 0;
m_aSlaves[MASTERSRV_0_5].m_pSlave = CreateSlave_0_5(this);
m_aSlaves[MASTERSRV_0_6].m_pSlave = CreateSlave_0_6(this);
m_aSlaves[MASTERSRV_0_7].m_pSlave = CreateSlave_0_7(this);
return 0;
}
int CMastersrv::Run()
{
dbg_msg("mastersrv", "started");
while(1)
{
m_NetOp.Update();
m_NetChecker.Update();
// process packets
CNetChunk Packet;
TOKEN Token;
int Version;
while(m_NetOp.Recv(&Packet, &Token, &Version))
{
// check if the server is banned
if(m_NetBan.IsBanned(&Packet.m_Address, 0, 0))
continue;
for(int s = 0; s < NUM_MASTERSRV; s++)
if(m_aSlaves[s].m_pSlave)
{
if(m_aSlaves[s].m_pSlave->ProcessMessage(SOCKET_OP, &Packet, Token, Version) != 0)
break;
}
}
// process packets
while(m_NetChecker.Recv(&Packet, &Token, &Version))
{
// check if the server is banned
if(m_NetBan.IsBanned(&Packet.m_Address, 0, 0))
continue;
for(int s = 0; s < NUM_MASTERSRV; s++)
if(m_aSlaves[s].m_pSlave)
if(m_aSlaves[s].m_pSlave->ProcessMessage(SOCKET_CHECKER, &Packet, Token, Version) != 0)
break;
}
int64 Now = time_get();
int64 Freq = time_freq();
if(m_BanRefreshTime < Now)
{
m_BanRefreshTime = Now + Freq * BAN_REFRESH_TIME;
ReloadBans();
}
if(m_PacketRefreshTime < Now)
{
m_PacketRefreshTime = Now + Freq * PACKET_REFRESH_TIME;
PurgeServers();
UpdateServers();
BuildPackets();
}
// be nice to the CPU
thread_sleep(1);
}
return 0;
}
void CMastersrv::UpdateServers()
{
int64 Now = time_get();
int64 Freq = time_freq();
for(int i = 0; i < m_NumCheckServers; i++)
{
CCheckServer *pCheck = &m_aCheckServers[i];
if(pCheck->m_TryTime + Freq < Now)
{
IMastersrvSlave *pSlave = m_aSlaves[pCheck->m_Version].m_pSlave;
dbg_assert(pSlave != 0, "attempting to access uninitalised slave");
if(pCheck->m_TryCount == 10)
{
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&pCheck->m_Address, aAddrStr, sizeof(aAddrStr), true);
char aAltAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&pCheck->m_AltAddress, aAltAddrStr, sizeof(aAltAddrStr), true);
dbg_msg("mastersrv", "check failed: %s (%s)", aAddrStr, aAltAddrStr);
// FAIL!!
pSlave->SendError(&pCheck->m_Address, pCheck->m_pSlaveUserData);
*pCheck = m_aCheckServers[m_NumCheckServers-1];
m_NumCheckServers--;
i--;
}
else
{
pCheck->m_TryCount++;
pCheck->m_TryTime = Now;
if(pCheck->m_TryCount&1)
pSlave->SendCheck(&pCheck->m_Address, pCheck->m_pSlaveUserData);
else
pSlave->SendCheck(&pCheck->m_AltAddress, pCheck->m_pSlaveUserData);
}
}
}
}
void CMastersrv::BuildPackets()
{
bool aPreparePacket[NUM_MASTERSRV];
for(int s = 0; s < NUM_MASTERSRV; s++)
{
m_aSlaves[s].m_NumPackets = 0;
aPreparePacket[s] = true;
for(int i = 0; i < MAX_PACKETS; i++)
m_aSlaves[s].m_aPackets[i].m_Size = 0;
}
for(int i = 0; i < m_NumServers; i++)
{
CServerEntry *pServer = &m_aServers[i];
CMastersrvSlave *pSlaveData = &m_aSlaves[pServer->m_Version];
IMastersrvSlave *pSlave = pSlaveData->m_pSlave;
CMastersrvSlave::CPacket *pPacket = &pSlaveData->m_aPackets[pSlaveData->m_NumPackets - 1];
dbg_assert(pSlave != 0, "attempting to access uninitalised slave");
int BytesWritten;
if(aPreparePacket[pServer->m_Version])
{
if(pSlaveData->m_NumPackets != 0)
{
BytesWritten = pSlave->BuildPacketFinalize(&pPacket->m_aData[pPacket->m_Size], NET_MAX_PAYLOAD - pPacket->m_Size);
dbg_assert(BytesWritten >= 0, "build packet finalisation failed");
}
pPacket = &pSlaveData->m_aPackets[pSlaveData->m_NumPackets];
pSlaveData->m_NumPackets++;
BytesWritten = pSlave->BuildPacketStart(&pPacket->m_aData[0], NET_MAX_PAYLOAD);
dbg_assert(BytesWritten >= 0, "build packet initialisation failed");
pPacket->m_Size += BytesWritten;
pSlaveData->m_NumPackets++;
aPreparePacket[pServer->m_Version] = false;
}
BytesWritten = pSlave->BuildPacketAdd(&pPacket->m_aData[pPacket->m_Size], NET_MAX_PAYLOAD - pPacket->m_Size,
&pServer->m_Address, pServer->m_pSlaveUserData);
if(BytesWritten < 0)
{
aPreparePacket[pServer->m_Version] = true;
i--;
continue;
}
pPacket->m_Size += BytesWritten;
}
for(int s = 0; s < NUM_MASTERSRV; s++)
{
CMastersrvSlave *pSlaveData = &m_aSlaves[s];
IMastersrvSlave *pSlave = pSlaveData->m_pSlave;
if(m_aSlaves[s].m_NumPackets > 0)
{
dbg_assert(pSlave != 0, "attempting to finalise packet for non-existant slave");
CMastersrvSlave::CPacket *pPacket = &pSlaveData->m_aPackets[pSlaveData->m_NumPackets - 1];
dbg_assert(pSlave->BuildPacketFinalize(&pPacket->m_aData[pPacket->m_Size], NET_MAX_PAYLOAD - pPacket->m_Size) >= 0, "final build packet finalisation failed");
}
}
/* CServerEntry *pCurrent = &m_aServers[0];
int ServersLeft = m_NumServers;
m_NumPackets = 0;
m_NumPacketsLegacy = 0;
int PacketIndex = 0;
int PacketIndexLegacy = 0;
while(ServersLeft-- && (m_NumPackets + m_NumPacketsLegacy) < MAX_PACKETS)
{
if(pCurrent->m_Type == SERVERTYPE_NORMAL)
{
if(PacketIndex % MAX_SERVERS_PER_PACKET == 0)
{
PacketIndex = 0;
m_NumPackets++;
}
// copy header
mem_copy(m_aPackets[m_NumPackets-1].m_Data.m_aHeader, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST));
// copy server addresses
if(pCurrent->m_Address.type == NETTYPE_IPV6)
{
mem_copy(m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aIp, pCurrent->m_Address.ip,
sizeof(m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aIp));
}
else
{
static char IPV4Mapping[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
mem_copy(m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aIp, IPV4Mapping, sizeof(IPV4Mapping));
m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aIp[12] = pCurrent->m_Address.ip[0];
m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aIp[13] = pCurrent->m_Address.ip[1];
m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aIp[14] = pCurrent->m_Address.ip[2];
m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aIp[15] = pCurrent->m_Address.ip[3];
}
m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aPort[0] = (pCurrent->m_Address.port>>8)&0xff;
m_aPackets[m_NumPackets-1].m_Data.m_aServers[PacketIndex].m_aPort[1] = pCurrent->m_Address.port&0xff;
PacketIndex++;
m_aPackets[m_NumPackets-1].m_Size = sizeof(SERVERBROWSE_LIST) + sizeof(CMastersrvAddr)*PacketIndex;
pCurrent++;
}
else if(pCurrent->m_Type == SERVERTYPE_LEGACY)
{
if(PacketIndexLegacy % MAX_SERVERS_PER_PACKET == 0)
{
PacketIndexLegacy = 0;
m_NumPacketsLegacy++;
}
// copy header
mem_copy(m_aPacketsLegacy[m_NumPacketsLegacy-1].m_Data.m_aHeader, SERVERBROWSE_LIST_LEGACY, sizeof(SERVERBROWSE_LIST_LEGACY));
// copy server addresses
mem_copy(m_aPacketsLegacy[m_NumPacketsLegacy-1].m_Data.m_aServers[PacketIndexLegacy].m_aIp, pCurrent->m_Address.ip,
sizeof(m_aPacketsLegacy[m_NumPacketsLegacy-1].m_Data.m_aServers[PacketIndexLegacy].m_aIp));
// 0.5 has the port in little endian on the network
m_aPacketsLegacy[m_NumPacketsLegacy-1].m_Data.m_aServers[PacketIndexLegacy].m_aPort[0] = pCurrent->m_Address.port&0xff;
m_aPacketsLegacy[m_NumPacketsLegacy-1].m_Data.m_aServers[PacketIndexLegacy].m_aPort[1] = (pCurrent->m_Address.port>>8)&0xff;
PacketIndexLegacy++;
m_aPacketsLegacy[m_NumPacketsLegacy-1].m_Size = sizeof(SERVERBROWSE_LIST_LEGACY) + sizeof(CMastersrvAddrLegacy)*PacketIndexLegacy;
pCurrent++;
}
else
{
*pCurrent = m_aServers[m_NumServers-1];
m_NumServers--;
dbg_msg("mastersrv", "error: server of invalid type, dropping it");
}
}
*/
}
int CMastersrv::Send(int Socket, const CNetChunk *pPacket, TOKEN PacketToken, int PacketVersion)
{
dbg_assert(Socket >= 0 && Socket < NUM_SOCKETS, "attempting to send via non-existant socket");
CNetClient *pNet = 0;
if(Socket == SOCKET_OP)
pNet = &m_NetOp;
else if(Socket == SOCKET_CHECKER)
pNet = &m_NetChecker;
pNet->Send((CNetChunk *)pPacket, PacketToken, PacketVersion);
return 0;
}
void CMastersrv::AddServer(const NETADDR *pAddr, void *pUserData, int Version)
{
dbg_assert(Version >= 0 && Version < NUM_MASTERSRV, "version out of range");
bool Found = false;
for(int i = 0; i < m_NumCheckServers && !Found; i++)
{
if((net_addr_comp(&m_aCheckServers[i].m_Address, pAddr) == 0
|| net_addr_comp(&m_aCheckServers[i].m_AltAddress, pAddr) == 0)
&& m_aCheckServers[i].m_Version == Version)
{
m_NumCheckServers--;
m_aCheckServers[i] = m_aCheckServers[m_NumCheckServers];
Found = true;
}
}
if(!Found) // only allow this for servers which are actually being checked
return;
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(pAddr, aAddrStr, sizeof(aAddrStr), true);
// see if server already exists in list
for(int i = 0; i < m_NumServers; i++)
{
if(net_addr_comp(&m_aServers[i].m_Address, pAddr) == 0 && m_aServers[i].m_Version == Version)
{
dbg_msg("mastersrv", "updated: %s", aAddrStr);
m_aServers[i].m_pSlaveUserData = pUserData;
m_aServers[i].m_Expire = time_get() + time_freq() * EXPIRE_TIME;
return;
}
}
// add server
if(m_NumServers == MAX_SERVERS)
{
dbg_msg("mastersrv", "error: mastersrv is full: %s", aAddrStr);
return;
}
dbg_msg("mastersrv", "added: %s", aAddrStr);
m_aServers[m_NumServers].m_Address = *pAddr;
m_aServers[m_NumServers].m_pSlaveUserData = pUserData;
m_aServers[m_NumServers].m_Expire = time_get() + time_freq() * EXPIRE_TIME;
m_aServers[m_NumServers].m_Version = Version;
m_NumServers++;
IMastersrvSlave *pSlave = m_aSlaves[Version].m_pSlave;
dbg_assert(pSlave != 0, "attempting to access uninitalised slave");
pSlave->SendOk(pAddr, pUserData);
}
void CMastersrv::AddCheckserver(const NETADDR *pAddr, const NETADDR *pAltAddr, void *pUserData, int Version)
{
dbg_assert(Version >= 0 && Version < NUM_MASTERSRV, "version out of range");
char aAddrStr[2 * NETADDR_MAXSTRSIZE + 3]; // 3 == sizeof(' ()')
char aTmp1[NETADDR_MAXSTRSIZE], aTmp2[NETADDR_MAXSTRSIZE];
net_addr_str(pAddr, aTmp1, sizeof(aTmp1), true);
net_addr_str(pAltAddr, aTmp2, sizeof(aTmp2), true);
str_format(aAddrStr, sizeof(aAddrStr), "%s (%s)", aTmp1, aTmp2);
// see if server already exists in list
for(int i = 0; i < m_NumCheckServers; i++)
{
if(net_addr_comp(&m_aCheckServers[i].m_Address, pAddr) == 0
&& m_aCheckServers[i].m_Version == Version)
{
dbg_msg("mastersrv/check", "warning: updated: %s", aAddrStr);
m_aCheckServers[i].m_AltAddress = *pAltAddr;
m_aCheckServers[i].m_pSlaveUserData = pUserData;
m_aCheckServers[i].m_TryCount = 0;
m_aCheckServers[i].m_TryTime = 0;
return;
}
}
// add server
if(m_NumCheckServers == MAX_CHECKSERVERS)
{
dbg_msg("mastersrv/check", "error: mastersrv is full: %s", aAddrStr);
return;
}
dbg_msg("mastersrv/check", "added: %s", aAddrStr);
m_aCheckServers[m_NumCheckServers].m_Address = *pAddr;
m_aCheckServers[m_NumCheckServers].m_AltAddress = *pAltAddr;
m_aCheckServers[m_NumCheckServers].m_pSlaveUserData = pUserData;
m_aCheckServers[m_NumCheckServers].m_TryCount = 0;
m_aCheckServers[m_NumCheckServers].m_TryTime = 0;
m_NumCheckServers++;
}
void CMastersrv::SendList(const NETADDR *pAddr, void *pUserData, int Version)
{
dbg_assert(Version >= 0 && Version < NUM_MASTERSRV, "version out of range");
IMastersrvSlave *pSlave = m_aSlaves[Version].m_pSlave;
dbg_assert(pSlave != 0, "attempting to access uninitalised slave");
for(int i = 0; i < m_aSlaves[Version].m_NumPackets; i++)
{
CMastersrvSlave::CPacket *pPacket = &m_aSlaves[Version].m_aPackets[i];
pSlave->SendList(pAddr, pPacket->m_aData, pPacket->m_Size, pUserData);
}
}
int CMastersrv::GetCount() const
{
dbg_msg("mastersrv", "requesting count, responding with %d", m_NumServers);
return m_NumServers;
}
void CMastersrv::PurgeServers()
{
int64 Now = time_get();
int i = 0;
while(i < m_NumServers)
{
if(m_aServers[i].m_Expire < Now)
{
// remove server
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&m_aServers[i].m_Address, aAddrStr, sizeof(aAddrStr), true);
dbg_msg("mastersrv", "expired: %s", aAddrStr);
m_aServers[i] = m_aServers[m_NumServers-1];
m_NumServers--;
}
else
i++;
}
}
void CMastersrv::ReloadBans()
{
m_NetBan.UnbanAll();
m_pConsole->ExecuteFile("master.cfg");
}
/*enum
{
MTU = 1400,
MAX_SERVERS_PER_PACKET=75,
MAX_PACKETS=16,
@ -407,7 +1022,7 @@ int main(int argc, const char **argv) // ignore_convention
// add it
AddCheckserver(&Packet.m_Address, &Alt, SERVERTYPE_NORMAL, Token);
}
/*else if(Packet.m_DataSize == sizeof(SERVERBROWSE_HEARTBEAT_LEGACY)+2 &&
else if(Packet.m_DataSize == sizeof(SERVERBROWSE_HEARTBEAT_LEGACY)+2 &&
mem_comp(Packet.m_pData, SERVERBROWSE_HEARTBEAT_LEGACY, sizeof(SERVERBROWSE_HEARTBEAT_LEGACY)) == 0)
{
NETADDR Alt;
@ -419,7 +1034,7 @@ int main(int argc, const char **argv) // ignore_convention
// add it
AddCheckserver(&Packet.m_Address, &Alt, SERVERTYPE_LEGACY);
}*/
}
else if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETCOUNT) &&
mem_comp(Packet.m_pData, SERVERBROWSE_GETCOUNT, sizeof(SERVERBROWSE_GETCOUNT)) == 0)
{
@ -435,7 +1050,7 @@ int main(int argc, const char **argv) // ignore_convention
m_CountData.m_Low = m_NumServers&0xff;
m_NetOp.Send(&p, Token);
}
/*else if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETCOUNT_LEGACY) &&
else if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETCOUNT_LEGACY) &&
mem_comp(Packet.m_pData, SERVERBROWSE_GETCOUNT_LEGACY, sizeof(SERVERBROWSE_GETCOUNT_LEGACY)) == 0)
{
dbg_msg("mastersrv", "count requested, responding with %d", m_NumServers);
@ -449,7 +1064,7 @@ int main(int argc, const char **argv) // ignore_convention
m_CountDataLegacy.m_High = (m_NumServers>>8)&0xff;
m_CountDataLegacy.m_Low = m_NumServers&0xff;
m_NetOp.Send(&p);
}*/
}
else if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETLIST) &&
mem_comp(Packet.m_pData, SERVERBROWSE_GETLIST, sizeof(SERVERBROWSE_GETLIST)) == 0)
{
@ -468,7 +1083,7 @@ int main(int argc, const char **argv) // ignore_convention
m_NetOp.Send(&p, Token);
}
}
/*else if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETLIST_LEGACY) &&
else if(Packet.m_DataSize == sizeof(SERVERBROWSE_GETLIST_LEGACY) &&
mem_comp(Packet.m_pData, SERVERBROWSE_GETLIST_LEGACY, sizeof(SERVERBROWSE_GETLIST_LEGACY)) == 0)
{
// someone requested the list
@ -485,7 +1100,7 @@ int main(int argc, const char **argv) // ignore_convention
p.m_pData = &m_aPacketsLegacy[i].m_Data;
m_NetOp.Send(&p);
}
}*/
}
}
// process m_aPackets
@ -543,3 +1158,5 @@ int main(int argc, const char **argv) // ignore_convention
return 0;
}
*/

View file

@ -2,14 +2,18 @@
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#ifndef MASTERSRV_MASTERSRV_H
#define MASTERSRV_MASTERSRV_H
static const int MASTERSERVER_PORT = 8300;
#include <engine/kernel.h>
#include <engine/shared/network.h>
/*static const int MASTERSERVER_PORT = 8300;
enum ServerType
{
SERVERTYPE_INVALID = -1,
SERVERTYPE_NORMAL,
SERVERTYPE_LEGACY
};
};*/
struct CMastersrvAddr
{
@ -17,6 +21,7 @@ struct CMastersrvAddr
unsigned char m_aPort[2];
};
static const unsigned char SERVERBROWSE_HEARTBEAT[] = {255, 255, 255, 255, 'b', 'e', 'a', '2'};
static const unsigned char SERVERBROWSE_GETLIST[] = {255, 255, 255, 255, 'r', 'e', 'q', '2'};
@ -34,6 +39,7 @@ static const unsigned char SERVERBROWSE_FWOK[] = {255, 255, 255, 255, 'f', 'w',
static const unsigned char SERVERBROWSE_FWERROR[] = {255, 255, 255, 255, 'f', 'w', 'e', 'r'};
/*
// packet headers for the 0.5 branch
struct CMastersrvAddrLegacy
@ -49,4 +55,119 @@ static const unsigned char SERVERBROWSE_LIST_LEGACY[] = {255, 255, 255, 255, 'l'
static const unsigned char SERVERBROWSE_GETCOUNT_LEGACY[] = {255, 255, 255, 255, 'c', 'o', 'u', 'n'};
static const unsigned char SERVERBROWSE_COUNT_LEGACY[] = {255, 255, 255, 255, 's', 'i', 'z', 'e'};
*/
class CNetChunk;
class IMastersrv;
enum
{
MASTERSERVER_PORT=8300,
};
class IMastersrv : public IInterface
{
MACRO_INTERFACE("mastersrv", 0)
public:
enum
{
MASTERSRV_0_7=0,
MASTERSRV_0_6,
MASTERSRV_0_5,
NUM_MASTERSRV,
SOCKET_OP=0,
SOCKET_CHECKER,
NUM_SOCKETS,
};
IMastersrv() {}
virtual ~IMastersrv() {}
virtual int Init() = 0;
virtual int Run() = 0;
virtual void AddServer(const NETADDR *pAddr, void *pUserData, int Version) = 0;
virtual void AddCheckserver(const NETADDR *pAddr, const NETADDR *pAltAddr, void *pUserData, int Version) = 0;
virtual void SendList(const NETADDR *pAddr, void *pUserData, int Version) = 0;
virtual int GetCount() const = 0;
virtual int Send(int Socket, const CNetChunk *pPacket, TOKEN PacketToken, int PacketVersion) = 0;
};
class IMastersrvSlave
{
public:
IMastersrvSlave(IMastersrv *pOwner, int Version) : m_pOwner(pOwner), m_Version(Version) {}
virtual ~IMastersrvSlave() {}
// hooks
void AddServer(const NETADDR *pAddr, void *pUserData) { m_pOwner->AddServer(pAddr, pUserData, m_Version); }
void AddCheckserver(const NETADDR *pAddr, const NETADDR *pAltAddr, void *pUserData) { m_pOwner->AddCheckserver(pAddr, pAltAddr, pUserData, m_Version); }
void SendList(const NETADDR *pAddr, void *pUserData) { m_pOwner->AddServer(pAddr, pUserData, m_Version); }
// interface for packet building
// these functions return number of bytes written
// if that number smaller than 0, an error is assumed
virtual int BuildPacketStart(void *pData, int MaxLength) { return 0; };
virtual int BuildPacketAdd(void *pData, int MaxLength, const NETADDR *pAddr, void *pUserData) = 0;
virtual int BuildPacketFinalize(void *pData, int MaxLength) { return 0; };
// interface for packet receiving
// this function shall return 0 if the packet should be furtherly processed
virtual int ProcessMessage(int Socket, const CNetChunk *pPacket, TOKEN PacketToken, int PacketVersion) = 0;
// interface for network
virtual void SendCheck(const NETADDR *pAddr, void *pUserData) = 0;
virtual void SendOk(const NETADDR *pAddr, void *pUserData) = 0;
virtual void SendError(const NETADDR *pAddr, void *pUserData) = 0;
virtual void SendList(const NETADDR *pAddr, const void *pData, int DataSize, void *pUserData) = 0;
static void NetaddrToMastersrv(CMastersrvAddr *pOut, const NETADDR *pIn);
protected:
IMastersrv *m_pOwner;
const int m_Version;
};
class IMastersrvSlaveAdv : public IMastersrvSlave
{
public:
IMastersrvSlaveAdv(IMastersrv *pOwner, int Version) : IMastersrvSlave(pOwner, Version) {}
virtual ~IMastersrvSlaveAdv() {}
virtual void SendCount(const NETADDR *pAddr, void *pUserData) { SendPacket(PACKET_COUNT, pAddr, pUserData); }
virtual void SendCheck(const NETADDR *pAddr, void *pUserData) { SendPacket(PACKET_CHECK, pAddr, pUserData); }
virtual void SendOk(const NETADDR *pAddr, void *pUserData) { SendPacket(PACKET_OK, pAddr, pUserData); }
virtual void SendError(const NETADDR *pAddr, void *pUserData) { SendPacket(PACKET_ERROR, pAddr, pUserData); }
virtual void SendList(const NETADDR *pAddr, const void *pData, int DataSize, void *pUserData)
{
m_aPackets[PACKET_LIST].m_DataSize = DataSize;
m_aPackets[PACKET_LIST].m_pData = pData;
SendPacket(PACKET_LIST, pAddr, pUserData);
}
protected:
virtual void SendPacket(int PacketType, const NETADDR *pAddr, void *pUserData) = 0;
enum
{
PACKET_COUNT=0,
PACKET_CHECK,
PACKET_OK,
PACKET_ERROR,
PACKET_LIST,
NUM_PACKETS,
};
CNetChunk m_aPackets[NUM_PACKETS];
};
IMastersrv *CreateMastersrv();
IMastersrvSlave *CreateSlave_0_5(IMastersrv *pOwner);
IMastersrvSlave *CreateSlave_0_6(IMastersrv *pOwner);
IMastersrvSlave *CreateSlave_0_7(IMastersrv *pOwner);
#endif

View file

@ -0,0 +1,10 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include "mastersrv.h"
IMastersrvSlave *CreateSlave_0_5(IMastersrv *pOwner)
{
return 0;
}

View file

@ -0,0 +1,10 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include "mastersrv.h"
IMastersrvSlave *CreateSlave_0_6(IMastersrv *pOwner)
{
return 0;
}

View file

@ -0,0 +1,133 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include "mastersrv.h"
class CMastersrvSlave_0_7 : public IMastersrvSlaveAdv
{
public:
CMastersrvSlave_0_7(IMastersrv *pOwner);
virtual ~CMastersrvSlave_0_7() {}
virtual int BuildPacketStart(void *pData, int MaxLength);
virtual int BuildPacketAdd(void *pData, int MaxLength, const NETADDR *pAddr, void *pUserData);
virtual int ProcessMessage(int Socket, const CNetChunk *pPacket, TOKEN PacketToken, int PacketVersion);
virtual void SendPacket(int PacketType, const NETADDR *pAddr, void *pUserData);
struct CCountPacketData
{
unsigned char m_Header[sizeof(SERVERBROWSE_COUNT)];
unsigned char m_High;
unsigned char m_Low;
} m_CountData;
};
CMastersrvSlave_0_7::CMastersrvSlave_0_7(IMastersrv *pOwner)
: IMastersrvSlaveAdv(pOwner, IMastersrv::MASTERSRV_0_7)
{
mem_copy(m_CountData.m_Header, SERVERBROWSE_COUNT, sizeof(m_CountData.m_Header));
for(int i = 0; i < NUM_PACKETS; i++)
{
m_aPackets[i].m_ClientID = -1;
m_aPackets[i].m_Flags = NETSENDFLAG_CONNLESS;
}
m_aPackets[PACKET_COUNT].m_DataSize = sizeof(m_CountData);
m_aPackets[PACKET_COUNT].m_pData = &m_CountData;
m_aPackets[PACKET_CHECK].m_DataSize = sizeof(SERVERBROWSE_FWCHECK);
m_aPackets[PACKET_CHECK].m_pData = SERVERBROWSE_FWCHECK;
m_aPackets[PACKET_OK].m_DataSize = sizeof(SERVERBROWSE_FWOK);
m_aPackets[PACKET_OK].m_pData = SERVERBROWSE_FWOK;
m_aPackets[PACKET_ERROR].m_DataSize = sizeof(SERVERBROWSE_FWERROR);
m_aPackets[PACKET_ERROR].m_pData = SERVERBROWSE_FWERROR;
}
int CMastersrvSlave_0_7::BuildPacketStart(void *pData, int MaxLength)
{
if(MaxLength < sizeof(SERVERBROWSE_GETLIST))
return -1;
mem_copy(pData, SERVERBROWSE_GETLIST, sizeof(SERVERBROWSE_GETLIST));
return sizeof(SERVERBROWSE_GETLIST);
}
int CMastersrvSlave_0_7::BuildPacketAdd(void *pData, int MaxLength, const NETADDR *pAddr, void *pUserData)
{
if(MaxLength < sizeof(CMastersrvAddr))
return -1;
NetaddrToMastersrv((CMastersrvAddr *)pData, pAddr);
return sizeof(CMastersrvAddr);
}
int CMastersrvSlave_0_7::ProcessMessage(int Socket, const CNetChunk *pPacket, TOKEN PacketToken, int PacketVersion)
{
if(PacketVersion != NET_PACKETVERSION || !(pPacket->m_Flags&NETSENDFLAG_CONNLESS))
return 0;
if(Socket == IMastersrv::SOCKET_OP)
{
if(pPacket->m_DataSize == sizeof(SERVERBROWSE_HEARTBEAT)+2 &&
mem_comp(pPacket->m_pData, SERVERBROWSE_HEARTBEAT, sizeof(SERVERBROWSE_HEARTBEAT)) == 0)
{
if(pPacket->m_Flags&NETSENDFLAG_STATELESS)
return -1;
NETADDR Alt;
unsigned char *d = (unsigned char *)pPacket->m_pData;
Alt = pPacket->m_Address;
Alt.port = (d[sizeof(SERVERBROWSE_HEARTBEAT)]<<8)
| d[sizeof(SERVERBROWSE_HEARTBEAT)+1];
AddCheckserver(&pPacket->m_Address, &Alt, (void *)PacketToken);
return 1;
}
else if(pPacket->m_DataSize == sizeof(SERVERBROWSE_GETCOUNT) &&
mem_comp(pPacket->m_pData, SERVERBROWSE_GETCOUNT, sizeof(SERVERBROWSE_GETCOUNT)) == 0)
{
int Count = m_pOwner->GetCount();
m_CountData.m_High = (Count>>8)&0xff;
m_CountData.m_Low = Count&0xff;
SendPacket(PACKET_COUNT, &pPacket->m_Address, (void *)PacketToken);
return 1;
}
else if(pPacket->m_DataSize == sizeof(SERVERBROWSE_GETLIST) &&
mem_comp(pPacket->m_pData, SERVERBROWSE_GETLIST, sizeof(SERVERBROWSE_GETLIST)) == 0)
{
if(pPacket->m_Flags&NETSENDFLAG_STATELESS)
return -1;
IMastersrvSlave::SendList(&pPacket->m_Address, (void *)PacketToken);
return 1;
}
}
else if(Socket == IMastersrv::SOCKET_CHECKER)
{
if(pPacket->m_DataSize == sizeof(SERVERBROWSE_FWRESPONSE) &&
mem_comp(pPacket->m_pData, SERVERBROWSE_FWRESPONSE, sizeof(SERVERBROWSE_FWRESPONSE)) == 0)
{
AddServer(&pPacket->m_Address, (void *)PacketToken);
return 1;
}
}
else
dbg_assert(0, "invalid socket type");
return 0;
}
void CMastersrvSlave_0_7::SendPacket(int PacketType, const NETADDR *pAddr, void *pUserData)
{
dbg_assert(PacketType >= 0 && PacketType < NUM_PACKETS, "invalid packet type");
m_aPackets[PacketType].m_Address = *pAddr;
m_pOwner->Send((PacketType != PACKET_CHECK) ? IMastersrv::SOCKET_OP : IMastersrv::SOCKET_CHECKER,
&m_aPackets[PacketType], (TOKEN) (long int) pUserData, NET_PACKETVERSION);
}
IMastersrvSlave *CreateSlave_0_7(IMastersrv *pOwner)
{
return new CMastersrvSlave_0_7(pOwner);
}