ddnet/src/engine/shared/masterserver.cpp

188 lines
4 KiB
C++

// copyright (c) 2007 magnus auvinen, see licence.txt for more info
#include <stdio.h> // sscanf
#include <base/system.h>
#include <engine/masterserver.h>
#include <engine/storage.h>
#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<IStorage>();
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<IStorage>();
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; }