// copyright (c) 2007 magnus auvinen, see licence.txt for more info #include // sscanf #include #include #include #include "engine.h" #include "linereader.h" class CMasterServer : public IEngineMasterServer { public: // master server functions struct CMasterInfo { char m_aHostname[128]; NETADDR m_Addr; CHostLookup m_Lookup; } ; CMasterInfo m_aMasterServers[MAX_MASTERSERVERS]; int m_NeedsUpdate; CEngine *m_pEngine; CMasterServer() { SetDefault(); m_NeedsUpdate = -1; m_pEngine = 0; } virtual int RefreshAddresses() { int i; if(m_NeedsUpdate != -1) return 0; dbg_msg("engine/mastersrv", "refreshing master server addresses"); // add lookup jobs for(i = 0; i < MAX_MASTERSERVERS; i++) m_pEngine->HostLookup(&m_aMasterServers[i].m_Lookup, m_aMasterServers[i].m_aHostname); m_NeedsUpdate = 1; return 0; } virtual void Update() { // check if we need to update if(m_NeedsUpdate != 1) return; m_NeedsUpdate = 0; for(int i = 0; i < MAX_MASTERSERVERS; i++) { if(m_aMasterServers[i].m_Lookup.m_Job.Status() != CJob::STATE_DONE) m_NeedsUpdate = 1; else { m_aMasterServers[i].m_Addr = m_aMasterServers[i].m_Lookup.m_Addr; m_aMasterServers[i].m_Addr.port = 8300; } } if(!m_NeedsUpdate) { dbg_msg("engine/mastersrv", "saving addresses"); Save(); } } virtual int IsRefreshing() { return m_NeedsUpdate; } virtual NETADDR GetAddr(int Index) { return m_aMasterServers[Index].m_Addr; } virtual const char *GetName(int Index) { return m_aMasterServers[Index].m_aHostname; } virtual void DumpServers() { for(int i = 0; i < MAX_MASTERSERVERS; i++) { dbg_msg("mastersrv", "#%d = %d.%d.%d.%d", i, m_aMasterServers[i].m_Addr.ip[0], m_aMasterServers[i].m_Addr.ip[1], m_aMasterServers[i].m_Addr.ip[2], m_aMasterServers[i].m_Addr.ip[3]); } } virtual void Init(class CEngine *pEngine) { m_pEngine = pEngine; } virtual void SetDefault() { mem_zero(m_aMasterServers, sizeof(m_aMasterServers)); for(int i = 0; i < MAX_MASTERSERVERS; i++) str_format(m_aMasterServers[i].m_aHostname, sizeof(m_aMasterServers[i].m_aHostname), "master%d.teeworlds.com", i+1); } virtual int Load() { CLineReader LineReader; IOHANDLE File; int Count = 0; IStorage *pStorage = Kernel()->RequestInterface(); if(!pStorage) return -1; // try to open file File = pStorage->OpenFile("masters.cfg", IOFLAG_READ); if(!File) return -1; LineReader.Init(File); while(1) { CMasterInfo Info = {{0}}; int aIp[4]; const char *pLine = LineReader.Get(); if(!pLine) break; // parse line if(sscanf(pLine, "%s %d.%d.%d.%d", Info.m_aHostname, &aIp[0], &aIp[1], &aIp[2], &aIp[3]) == 5) { Info.m_Addr.ip[0] = (unsigned char)aIp[0]; Info.m_Addr.ip[1] = (unsigned char)aIp[1]; Info.m_Addr.ip[2] = (unsigned char)aIp[2]; Info.m_Addr.ip[3] = (unsigned char)aIp[3]; Info.m_Addr.port = 8300; if(Count != MAX_MASTERSERVERS) { m_aMasterServers[Count] = Info; Count++; } //else // dbg_msg("engine/mastersrv", "warning: skipped master server '%s' due to limit of %d", pLine, MAX_MASTERSERVERS); } //else // dbg_msg("engine/mastersrv", "warning: couldn't parse master server '%s'", pLine); } io_close(File); return 0; } virtual int Save() { IOHANDLE File; IStorage *pStorage = Kernel()->RequestInterface(); if(!pStorage) return -1; // try to open file File = pStorage->OpenFile("masters.cfg", IOFLAG_WRITE); if(!File) return -1; for(int i = 0; i < MAX_MASTERSERVERS; i++) { char aBuf[1024]; str_format(aBuf, sizeof(aBuf), "%s %d.%d.%d.%d\n", m_aMasterServers[i].m_aHostname, m_aMasterServers[i].m_Addr.ip[0], m_aMasterServers[i].m_Addr.ip[1], m_aMasterServers[i].m_Addr.ip[2], m_aMasterServers[i].m_Addr.ip[3]); io_write(File, aBuf, str_length(aBuf)); } io_close(File); return 0; } }; IEngineMasterServer *CreateEngineMasterServer() { return new CMasterServer; }