From 1c591793b0992aab135eed6a555f172628bb1826 Mon Sep 17 00:00:00 2001 From: heinrich5991 Date: Fri, 27 Jul 2012 15:51:31 +0200 Subject: [PATCH] refactored mastersrv, working for 0.7 only currently --- src/engine/shared/network.h | 2 +- src/mastersrv/mastersrv.cpp | 631 ++++++++++++++++++++++++++++++++++- src/mastersrv/mastersrv.h | 125 ++++++- src/mastersrv/mastersrv5.cpp | 10 + src/mastersrv/mastersrv6.cpp | 10 + src/mastersrv/mastersrv7.cpp | 133 ++++++++ 6 files changed, 901 insertions(+), 10 deletions(-) create mode 100644 src/mastersrv/mastersrv5.cpp create mode 100644 src/mastersrv/mastersrv6.cpp create mode 100644 src/mastersrv/mastersrv7.cpp diff --git a/src/engine/shared/network.h b/src/engine/shared/network.h index b5b58f36a..473a4b9c4 100644 --- a/src/engine/shared/network.h +++ b/src/engine/shared/network.h @@ -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, diff --git a/src/mastersrv/mastersrv.cpp b/src/mastersrv/mastersrv.cpp index 482471b79..78e173c6f 100644 --- a/src/mastersrv/mastersrv.cpp +++ b/src/mastersrv/mastersrv.cpp @@ -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(); + + m_NetBan.Init(m_pConsole, Kernel()->RequestInterface()); + + 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; } +*/ + diff --git a/src/mastersrv/mastersrv.h b/src/mastersrv/mastersrv.h index 38e5ab277..105543da0 100644 --- a/src/mastersrv/mastersrv.h +++ b/src/mastersrv/mastersrv.h @@ -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 +#include + +/*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 diff --git a/src/mastersrv/mastersrv5.cpp b/src/mastersrv/mastersrv5.cpp new file mode 100644 index 000000000..4a8cc7deb --- /dev/null +++ b/src/mastersrv/mastersrv5.cpp @@ -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; +} + diff --git a/src/mastersrv/mastersrv6.cpp b/src/mastersrv/mastersrv6.cpp new file mode 100644 index 000000000..be2cdbe17 --- /dev/null +++ b/src/mastersrv/mastersrv6.cpp @@ -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; +} + diff --git a/src/mastersrv/mastersrv7.cpp b/src/mastersrv/mastersrv7.cpp new file mode 100644 index 000000000..929f42a46 --- /dev/null +++ b/src/mastersrv/mastersrv7.cpp @@ -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); +} +