Merge branch 'master' of git://github.com/oy/teeworlds into DDRace

Conflicts:
	src/engine/console.h
	src/engine/server/server.cpp
	src/engine/server/server.h
	src/engine/shared/config.h
	src/engine/shared/console.cpp
	src/engine/shared/console.h
	src/engine/shared/network_server.cpp
@heinrich5991 todo
This commit is contained in:
GreYFoX 2012-01-01 00:00:00 +02:00
commit ee670118a5
41 changed files with 1575 additions and 829 deletions

View file

@ -135,7 +135,7 @@ static IOHANDLE logfile = 0;
static void logger_file(const char *line)
{
io_write(logfile, line, strlen(line));
io_write(logfile, "\n", 1);
io_write_newline(logfile);
io_flush(logfile);
}
@ -152,8 +152,6 @@ void dbg_logger_file(const char *filename)
}
/* */
int memory_alloced = 0;
typedef struct MEMHEADER
{
const char *filename;
@ -175,8 +173,10 @@ void *mem_alloc_debug(const char *filename, int line, unsigned size, unsigned al
{
/* TODO: fix alignment */
/* TODO: add debugging */
MEMTAIL *tail;
MEMHEADER *header = (struct MEMHEADER *)malloc(size+sizeof(MEMHEADER)+sizeof(MEMTAIL));
MEMTAIL *tail = (struct MEMTAIL *)(((char*)(header+1))+size);
dbg_assert(header != 0, "mem_alloc failure");
tail = (struct MEMTAIL *)(((char*)(header+1))+size);
header->size = size;
header->filename = filename;
header->line = line;
@ -232,8 +232,9 @@ void mem_debug_dump(IOHANDLE file)
{
while(header)
{
str_format(buf, sizeof(buf), "%s(%d): %d\n", header->filename, header->line, header->size);
str_format(buf, sizeof(buf), "%s(%d): %d", header->filename, header->line, header->size);
io_write(file, buf, strlen(buf));
io_write_newline(file);
header = header->next;
}
@ -356,6 +357,15 @@ unsigned io_write(IOHANDLE io, const void *buffer, unsigned size)
return fwrite(buffer, 1, size, (FILE*)io);
}
unsigned io_write_newline(IOHANDLE io)
{
#if defined(CONF_FAMILY_WINDOWS)
return fwrite("\r\n", 1, 2, (FILE*)io);
#else
return fwrite("\n", 1, 1, (FILE*)io);
#endif
}
int io_close(IOHANDLE io)
{
fclose((FILE*)io);
@ -595,18 +605,18 @@ int net_addr_comp(const NETADDR *a, const NETADDR *b)
return mem_comp(a, b, sizeof(NETADDR));
}
void net_addr_str(const NETADDR *addr, char *string, int max_length)
void net_addr_str(const NETADDR *addr, char *string, int max_length, int add_port)
{
if(addr->type == NETTYPE_IPV4)
{
if(addr->port != 0)
if(add_port != 0)
str_format(string, max_length, "%d.%d.%d.%d:%d", addr->ip[0], addr->ip[1], addr->ip[2], addr->ip[3], addr->port);
else
str_format(string, max_length, "%d.%d.%d.%d", addr->ip[0], addr->ip[1], addr->ip[2], addr->ip[3]);
}
else if(addr->type == NETTYPE_IPV6)
{
if(addr->port != 0)
if(add_port != 0)
str_format(string, max_length, "[%x:%x:%x:%x:%x:%x:%x:%x]:%d",
(addr->ip[0]<<8)|addr->ip[1], (addr->ip[2]<<8)|addr->ip[3], (addr->ip[4]<<8)|addr->ip[5], (addr->ip[6]<<8)|addr->ip[7],
(addr->ip[8]<<8)|addr->ip[9], (addr->ip[10]<<8)|addr->ip[11], (addr->ip[12]<<8)|addr->ip[13], (addr->ip[14]<<8)|addr->ip[15],
@ -1510,7 +1520,7 @@ int net_socket_read_wait(NETSOCKET sock, int time)
return 0;
}
unsigned time_timestamp()
int time_timestamp()
{
return time(0);
}

View file

@ -239,6 +239,18 @@ unsigned io_skip(IOHANDLE io, int size);
*/
unsigned io_write(IOHANDLE io, const void *buffer, unsigned size);
/*
Function: io_write_newline
Writes newline to file.
Parameters:
io - Handle to the file.
Returns:
Number of bytes written.
*/
unsigned io_write_newline(IOHANDLE io);
/*
Function: io_seek
Seeks to a specified offset in the file.
@ -425,7 +437,7 @@ int64 time_freq();
Returns:
The time as a UNIX timestamp
*/
unsigned time_timestamp();
int time_timestamp();
/* Group: Network General */
typedef struct
@ -499,12 +511,13 @@ int net_addr_comp(const NETADDR *a, const NETADDR *b);
addr - Address to turn into a string.
string - Buffer to fill with the string.
max_length - Maximum size of the string.
add_port - add port to string or not
Remarks:
- The string will always be zero terminated
*/
void net_addr_str(const NETADDR *addr, char *string, int max_length);
void net_addr_str(const NETADDR *addr, char *string, int max_length, int add_port);
/*
Function: net_addr_from_str
@ -1130,25 +1143,6 @@ void mem_debug_dump(IOHANDLE file);
void swap_endian(void *data, unsigned elem_size, unsigned num);
/* Group: Debug levels */
//by format
enum {
DBG_FMT_RAW = 1, //raw output
DBG_FMT_TIME = 2, //show time
DBG_FMT_SYS = 3, //show sys
DBG_FMT_FULL = 4 //show both
};
enum {
DBG_LEVEL_IMPORTANT = 0, //important always showed messages
DBG_LEVEL_ERROR = 1, //error messages
DBG_LEVEL_WARNING = 2, //warning messages
DBG_LEVEL_MSG = 3, //extra debug messages
DBG_LEVEL_INFO = 4 //info messages
};
#define DBG_LEVEL_LOW DBG_LEVEL_IMPORTANT
#define DBG_LEVEL_HIGH DBG_LEVEL_INFO
typedef void (*DBG_LOGGER)(const char *line);
void dbg_logger(DBG_LOGGER logger);

View file

@ -546,6 +546,7 @@ void CClient::DisconnectWithReason(const char *pReason)
//
m_RconAuthed = 0;
m_UseTempRconCommands = 0;
m_pConsole->DeregisterTempAll();
m_NetClient.Disconnect(pReason);
SetState(IClient::STATE_OFFLINE);
@ -967,7 +968,7 @@ void CClient::ProcessConnlessPacket(CNetChunk *pPacket)
Info.m_NumPlayers < 0 || Info.m_NumPlayers > Info.m_NumClients || Info.m_MaxPlayers < 0 || Info.m_MaxPlayers > Info.m_MaxClients)
return;
net_addr_str(&pPacket->m_Address, Info.m_aAddress, sizeof(Info.m_aAddress));
net_addr_str(&pPacket->m_Address, Info.m_aAddress, sizeof(Info.m_aAddress), true);
for(int i = 0; i < Info.m_NumClients; i++)
{
@ -1156,9 +1157,12 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
int Result = Unpacker.GetInt();
if(Unpacker.Error() == 0)
m_RconAuthed = Result;
int Old = m_UseTempRconCommands;
m_UseTempRconCommands = Unpacker.GetInt();
if(Unpacker.Error() != 0)
m_UseTempRconCommands = 0;
if(Old != 0 && m_UseTempRconCommands == 0)
m_pConsole->DeregisterTempAll();
}
else if(Msg == NETMSG_RCON_LINE)
{

View file

@ -370,7 +370,6 @@ void CServerBrowser::SetInfo(CServerEntry *pEntry, const CServerInfo &Info)
}*/
pEntry->m_GotInfo = 1;
Sort();
}
CServerBrowser::CServerEntry *CServerBrowser::Add(const NETADDR &Addr)
@ -388,7 +387,7 @@ CServerBrowser::CServerEntry *CServerBrowser::Add(const NETADDR &Addr)
pEntry->m_Info.m_NetAddr = Addr;
pEntry->m_Info.m_Latency = 999;
net_addr_str(&Addr, pEntry->m_Info.m_aAddress, sizeof(pEntry->m_Info.m_aAddress));
net_addr_str(&Addr, pEntry->m_Info.m_aAddress, sizeof(pEntry->m_Info.m_aAddress), true);
str_copy(pEntry->m_Info.m_aName, pEntry->m_Info.m_aAddress, sizeof(pEntry->m_Info.m_aName));
// check if it's a favorite
@ -528,7 +527,7 @@ void CServerBrowser::RequestImpl(const NETADDR &Addr, CServerEntry *pEntry) cons
if(g_Config.m_Debug)
{
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr), true);
char aBuf[256];
str_format(aBuf, sizeof(aBuf),"requesting server info from %s", aAddrStr);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", aBuf);
@ -669,7 +668,7 @@ void CServerBrowser::AddFavorite(const NETADDR &Addr)
if(g_Config.m_Debug)
{
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr), true);
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "added fav, %s", aAddrStr);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", aBuf);
@ -723,12 +722,11 @@ void CServerBrowser::ConfigSaveCallback(IConfig *pConfig, void *pUserData)
{
CServerBrowser *pSelf = (CServerBrowser *)pUserData;
int i;
char aAddrStr[128];
char aBuffer[256];
for(i = 0; i < pSelf->m_NumFavoriteServers; i++)
for(int i = 0; i < pSelf->m_NumFavoriteServers; i++)
{
net_addr_str(&pSelf->m_aFavoriteServers[i], aAddrStr, sizeof(aAddrStr));
net_addr_str(&pSelf->m_aFavoriteServers[i], aAddrStr, sizeof(aAddrStr), true);
str_format(aBuffer, sizeof(aBuffer), "add_favorite %s", aAddrStr);
pConfig->WriteLine(aBuffer);
}

View file

@ -285,7 +285,8 @@ class CTextRender : public IEngineTextRender
Oldest = i;
}
if(time_get()-pSizeData->m_aCharacters[Oldest].m_TouchTime < time_freq())
if(time_get()-pSizeData->m_aCharacters[Oldest].m_TouchTime < time_freq() &&
(pSizeData->m_NumXChars < MAX_CHARACTERS || pSizeData->m_NumYChars < MAX_CHARACTERS))
{
IncreaseTextureSize(pSizeData);
return GetSlot(pSizeData);

View file

@ -84,6 +84,7 @@ public:
virtual bool LineIsValid(const char *pStr) = 0;
virtual void ExecuteLine(const char *Sptr, int ClientID = -1) = 0;
virtual void ExecuteLineFlag(const char *Sptr, int FlasgMask) = 0;
virtual void ExecuteLineStroked(int Stroke, const char *pStr, int ClientID = -1) = 0;
virtual void ExecuteFile(const char *pFilename, int ClientID = -1) = 0;

1
src/engine/external/pnglite/VERSION vendored Normal file
View file

@ -0,0 +1 @@
0.1.17

1
src/engine/external/wavpack/VERSION vendored Normal file
View file

@ -0,0 +1 @@
4.40

View file

@ -55,6 +55,12 @@ public:
virtual void SnapSetStaticsize(int ItemType, int Size) = 0;
enum
{
RCON_CID_SERV=-1,
RCON_CID_VOTE=-2,
};
virtual void SetRconCID(int ClientID) = 0;
virtual bool IsAuthed(int ClientID) = 0;
virtual void Kick(int ClientID, const char *pReason) = 0;

View file

@ -19,6 +19,7 @@
#include <engine/shared/econ.h>
#include <engine/shared/filecollection.h>
#include <engine/shared/mapchecker.h>
#include <engine/shared/netban.h>
#include <engine/shared/network.h>
#include <engine/shared/packer.h>
#include <engine/shared/protocol.h>
@ -45,37 +46,48 @@
static const char SERVER_BANMASTERFILE[] = "banmasters.cfg";
static const char *StrLtrim(const char *pStr)
{
while(*pStr && *pStr >= 0 && *pStr <= 32)
pStr++;
return pStr;
}
static void StrRtrim(char *pStr)
{
int i = str_length(pStr);
while(i >= 0)
{
if(pStr[i] < 0 || pStr[i] > 32)
break;
pStr[i] = 0;
i--;
}
}
static int StrAllnum(const char *pStr)
static const char *StrUTF8Ltrim(const char *pStr)
{
while(*pStr)
{
if(!(*pStr >= '0' && *pStr <= '9'))
return 0;
pStr++;
const char *pStrOld = pStr;
int Code = str_utf8_decode(&pStr);
// check if unicode is not empty
if(Code > 0x20 && Code != 0xA0 && Code != 0x034F && (Code < 0x2000 || Code > 0x200F) && (Code < 0x2028 || Code > 0x202F) &&
(Code < 0x205F || Code > 0x2064) && (Code < 0x206A || Code > 0x206F) && (Code < 0xFE00 || Code > 0xFE0F) &&
Code != 0xFEFF && (Code < 0xFFF9 || Code > 0xFFFC))
{
return pStrOld;
}
}
return 1;
return pStr;
}
static void StrUTF8Rtrim(char *pStr)
{
const char *p = pStr;
const char *pEnd = 0;
while(*p)
{
const char *pStrOld = p;
int Code = str_utf8_decode(&p);
// check if unicode is not empty
if(Code > 0x20 && Code != 0xA0 && Code != 0x034F && (Code < 0x2000 || Code > 0x200F) && (Code < 0x2028 || Code > 0x202F) &&
(Code < 0x205F || Code > 0x2064) && (Code < 0x206A || Code > 0x206F) && (Code < 0xFE00 || Code > 0xFE0F) &&
Code != 0xFEFF && (Code < 0xFFF9 || Code > 0xFFFC))
{
pEnd = 0;
}
else if(pEnd == 0)
pEnd = pStrOld;
}
if(pEnd != 0)
*(const_cast<char *>(pEnd)) = 0;
}
CSnapIDPool::CSnapIDPool()
{
Reset();
@ -164,6 +176,115 @@ void CSnapIDPool::FreeID(int ID)
}
}
void CServerBan::Init(IConsole *pConsole, IStorage *pStorage, CServer* pServer)
{
CNetBan::Init(pConsole, pStorage);
m_pServer = pServer;
// overwrites base command, todo: improve this
Console()->Register("ban", "s?ir", CFGFLAG_SERVER|CFGFLAG_STORE, ConBanExt, this, "Ban player with ip/client id for x minutes for any reason");
}
template<class T>
int CServerBan::BanExt(T *pBanPool, const typename T::CDataType *pData, int Seconds, const char *pReason)
{
// validate address
if(Server()->m_RconClientID >= 0 && Server()->m_RconClientID < MAX_CLIENTS &&
Server()->m_aClients[Server()->m_RconClientID].m_State != CServer::CClient::STATE_EMPTY)
{
if(NetMatch(pData, Server()->m_NetServer.ClientAddr(Server()->m_RconClientID)))
{
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (you can't ban yourself)");
return -1;
}
for(int i = 0; i < MAX_CLIENTS; ++i)
{
if(i == Server()->m_RconClientID || Server()->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY)
continue;
if(Server()->m_aClients[i].m_Authed >= Server()->m_RconAuthLevel && NetMatch(pData, Server()->m_NetServer.ClientAddr(i)))
{
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (command denied)");
return -1;
}
}
}
else if(Server()->m_RconClientID == IServer::RCON_CID_VOTE)
{
for(int i = 0; i < MAX_CLIENTS; ++i)
{
if(Server()->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY)
continue;
if(Server()->m_aClients[i].m_Authed != CServer::AUTHED_NO && NetMatch(pData, Server()->m_NetServer.ClientAddr(i)))
{
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (command denied)");
return -1;
}
}
}
int Result = Ban(pBanPool, pData, Seconds, pReason);
if(Result != 0)
return Result;
// drop banned clients
typename T::CDataType Data = *pData;
for(int i = 0; i < MAX_CLIENTS; ++i)
{
if(Server()->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY)
continue;
if(NetMatch(&Data, Server()->m_NetServer.ClientAddr(i)))
{
CNetHash NetHash(&Data);
char aBuf[256];
MakeBanInfo(pBanPool->Find(&Data, &NetHash), aBuf, sizeof(aBuf), MSGTYPE_PLAYER);
Server()->m_NetServer.Drop(i, aBuf);
}
}
return Result;
}
int CServerBan::BanAddr(const NETADDR *pAddr, int Seconds, const char *pReason)
{
return BanExt(&m_BanAddrPool, pAddr, Seconds, pReason);
}
int CServerBan::BanRange(const CNetRange *pRange, int Seconds, const char *pReason)
{
if(pRange->IsValid())
return BanExt(&m_BanRangePool, pRange, Seconds, pReason);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (invalid range)");
return -1;
}
void CServerBan::ConBanExt(IConsole::IResult *pResult, void *pUser)
{
CServerBan *pThis = static_cast<CServerBan *>(pUser);
const char *pStr = pResult->GetString(0);
int Minutes = pResult->NumArguments()>1 ? clamp(pResult->GetInteger(1), 0, 44640) : 30;
const char *pReason = pResult->NumArguments()>2 ? pResult->GetString(2) : "No reason given";
if(StrAllnum(pStr))
{
int ClientID = str_toint(pStr);
if(ClientID < 0 || ClientID >= MAX_CLIENTS || pThis->Server()->m_aClients[ClientID].m_State == CServer::CClient::STATE_EMPTY)
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (invalid client id)");
else
pThis->BanAddr(pThis->Server()->m_NetServer.ClientAddr(ClientID), Minutes*60, pReason);
}
else
ConBan(pResult, pUser);
}
void CServer::CClient::Reset()
{
// reset input
@ -193,7 +314,7 @@ CServer::CServer() : m_DemoRecorder(&m_SnapshotDelta)
m_MapReload = 0;
m_RconClientID = -1;
m_RconClientID = IServer::RCON_CID_SERV;
m_RconAuthLevel = AUTHED_ADMIN;
Init();
@ -205,8 +326,8 @@ int CServer::TrySetClientName(int ClientID, const char *pName)
char aTrimmedName[64];
// trim the name
str_copy(aTrimmedName, StrLtrim(pName), sizeof(aTrimmedName));
StrRtrim(aTrimmedName);
str_copy(aTrimmedName, StrUTF8Ltrim(pName), sizeof(aTrimmedName));
StrUTF8Rtrim(aTrimmedName);
// check if new and old name are the same
if(m_aClients[ClientID].m_aName[0] && str_comp(m_aClients[ClientID].m_aName, aTrimmedName) == 0)
@ -337,6 +458,11 @@ int CServer::Init()
return 0;
}
void CServer::SetRconCID(int ClientID)
{
m_RconClientID = ClientID;
}
bool CServer::IsAuthed(int ClientID)
{
return m_aClients[ClientID].m_Authed;
@ -359,11 +485,7 @@ int CServer::GetClientInfo(int ClientID, CClientInfo *pInfo)
void CServer::GetClientAddr(int ClientID, char *pAddrStr, int Size)
{
if(ClientID >= 0 && ClientID < MAX_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_INGAME)
{
NETADDR Addr = m_NetServer.ClientAddr(ClientID);
Addr.port = 0;
net_addr_str(&Addr, pAddrStr, Size);
}
net_addr_str(m_NetServer.ClientAddr(ClientID), pAddrStr, Size, false);
}
@ -601,7 +723,6 @@ int CServer::NewClientCallback(int ClientID, void *pUser)
pThis->m_aClients[ClientID].m_Authed = AUTHED_NO;
pThis->m_aClients[ClientID].m_AuthTries = 0;
pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
memset(&pThis->m_aClients[ClientID].m_Addr, 0, sizeof(NETADDR));
pThis->m_aClients[ClientID].Reset();
return 0;
}
@ -610,9 +731,8 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser)
{
CServer *pThis = (CServer *)pUser;
NETADDR Addr = pThis->m_NetServer.ClientAddr(ClientID);
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
net_addr_str(pThis->m_NetServer.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true);
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "client dropped. cid=%d addr=%s reason='%s'", ClientID, aAddrStr, pReason);
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf);
@ -629,7 +749,6 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser)
pThis->m_aClients[ClientID].m_AuthTries = 0;
pThis->m_aClients[ClientID].m_pRconCmdToSend = 0;
pThis->m_aPrevStates[ClientID] = CClient::STATE_EMPTY;
memset(&pThis->m_aClients[ClientID].m_Addr, 0, sizeof(NETADDR));
pThis->m_aClients[ClientID].m_Snapshots.PurgeAll();
return 0;
}
@ -708,7 +827,6 @@ void CServer::UpdateClientRconCommands()
void CServer::ProcessClientPacket(CNetChunk *pPacket)
{
int ClientID = pPacket->m_ClientID;
NETADDR Addr;
CUnpacker Unpacker;
Unpacker.Reset(pPacket->m_pData, pPacket->m_DataSize);
@ -794,9 +912,8 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
{
if(m_aClients[ClientID].m_State == CClient::STATE_CONNECTING)
{
Addr = m_NetServer.ClientAddr(ClientID);
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
net_addr_str(m_NetServer.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true);
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "player is ready. ClientID=%x addr=%s", ClientID, aAddrStr);
@ -810,10 +927,8 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
{
if(m_aClients[ClientID].m_State == CClient::STATE_READY && GameServer()->IsClientReady(ClientID))
{
Addr = m_NetServer.ClientAddr(ClientID);
m_aClients[ClientID].m_Addr = Addr;
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
net_addr_str(m_NetServer.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true);
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "player has entered the game. ClientID=%x addr=%s", ClientID, aAddrStr);
@ -886,9 +1001,9 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
m_RconClientID = ClientID;
m_RconAuthLevel = m_aClients[ClientID].m_Authed;
Console()->SetAccessLevel(m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : m_aClients[ClientID].m_Authed == AUTHED_MOD ? IConsole::ACCESS_LEVEL_MOD : IConsole::ACCESS_LEVEL_USER);
Console()->ExecuteLine(pCmd, ClientID);
Console()->ExecuteLineFlag(pCmd, CFGFLAG_SERVER);
Console()->SetAccessLevel(IConsole::ACCESS_LEVEL_ADMIN);
m_RconClientID = -1;
m_RconClientID = IServer::RCON_CID_SERV;
m_RconAuthLevel = AUTHED_ADMIN;
}
}
@ -955,10 +1070,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
if(!g_Config.m_SvRconBantime)
m_NetServer.Drop(ClientID, "Too many remote console authentication tries");
else
{
NETADDR Addr = m_NetServer.ClientAddr(ClientID);
BanAdd(Addr, g_Config.m_SvRconBantime*60, "Too many remote console authentication tries");
}
m_ServerBan.BanAddr(m_NetServer.ClientAddr(ClientID), g_Config.m_SvRconBantime*60, "Too many remote console authentication tries");
}
}
else
@ -1002,7 +1114,7 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket)
}
}
void CServer::SendServerInfo(NETADDR *pAddr, int Token)
void CServer::SendServerInfo(const NETADDR *pAddr, int Token)
{
CNetChunk Packet;
CPacker p;
@ -1071,38 +1183,10 @@ void CServer::UpdateServerInfo()
for(int i = 0; i < MAX_CLIENTS; ++i)
{
if(m_aClients[i].m_State != CClient::STATE_EMPTY)
{
NETADDR Addr = m_NetServer.ClientAddr(i);
SendServerInfo(&Addr, -1);
}
SendServerInfo(m_NetServer.ClientAddr(i), -1);
}
}
int CServer::BanAdd(NETADDR Addr, int Seconds, const char *pReason)
{
Addr.port = 0;
char aAddrStr[128];
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
char aBuf[256];
if(Seconds)
str_format(aBuf, sizeof(aBuf), "banned %s for %d minutes", aAddrStr, Seconds/60);
else
str_format(aBuf, sizeof(aBuf), "banned %s for life", aAddrStr);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
return m_NetServer.BanAdd(Addr, Seconds, pReason);
}
int CServer::BanRemove(NETADDR Addr)
{
return m_NetServer.BanRemove(Addr);
}
int CServer::BanRemoveAll()
{
return m_NetServer.BanRemoveAll();
}
void CServer::PumpNetwork()
{
@ -1151,7 +1235,8 @@ void CServer::PumpNetwork()
return;
}
m_NetServer.BanAdd(Addr, g_Config.m_SvGlobalBantime * 60, aReason);
// TODO(heinrich5991): fix banmaster global ban addition
//m_NetServer.BanAdd(Addr, g_Config.m_SvGlobalBantime * 60, aReason);
dbg_msg("globalbans", "added ban, ip=%s, reason='%s'", aIp, aReason);
}
}
@ -1160,6 +1245,7 @@ void CServer::PumpNetwork()
ProcessClientPacket(&Packet);
}
m_ServerBan.Update();
m_Econ.Update();
}
@ -1262,7 +1348,7 @@ int CServer::Run()
BindAddr.port = g_Config.m_SvPort;
}
if(!m_NetServer.Open(BindAddr, g_Config.m_SvMaxClients, g_Config.m_SvMaxClientsPerIP, 0))
if(!m_NetServer.Open(BindAddr, &m_ServerBan, g_Config.m_SvMaxClients, g_Config.m_SvMaxClientsPerIP, 0))
{
dbg_msg("server", "couldn't open socket. port might already be in use");
return -1;
@ -1270,7 +1356,8 @@ int CServer::Run()
m_NetServer.SetCallbacks(NewClientCallback, DelClientCallback, this);
m_Econ.Init(Console());
m_ServerBan.Init(Console(), Storage(), this);
m_Econ.Init(Console(), &m_ServerBan);
Console()->ExecuteFile(SERVER_BANMASTERFILE);
@ -1435,170 +1522,23 @@ void CServer::ConKick(IConsole::IResult *pResult, void *pUser)
((CServer *)pUser)->Kick(pResult->GetInteger(0), "Kicked by console");
}
void CServer::ConBan(IConsole::IResult *pResult, void *pUser)
{
NETADDR Addr;
CServer *pServer = (CServer *)pUser;
const char *pStr = pResult->GetString(0);
int Minutes = 30;
const char *pReason = "No reason given";
if(pResult->NumArguments() > 1)
Minutes = min(max(0, pResult->GetInteger(1)), 1000000); // todo: fix this in year 2035
if(pResult->NumArguments() > 2)
pReason = pResult->GetString(2);
if(net_addr_from_str(&Addr, pStr) == 0)
{
if(pServer->m_RconClientID >= 0 && pServer->m_RconClientID < MAX_CLIENTS && pServer->m_aClients[pServer->m_RconClientID].m_State != CClient::STATE_EMPTY)
{
NETADDR AddrCheck = pServer->m_NetServer.ClientAddr(pServer->m_RconClientID);
Addr.port = AddrCheck.port = 0;
if(net_addr_comp(&Addr, &AddrCheck) == 0)
{
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "you can't ban yourself");
return;
}
for(int i = 0; i < MAX_CLIENTS; ++i)
{
if(i == pServer->m_RconClientID)
continue;
AddrCheck = pServer->m_NetServer.ClientAddr(i);
AddrCheck.port = 0;
if(net_addr_comp(&Addr, &AddrCheck) == 0 && pServer->m_aClients[i].m_Authed > pServer->m_RconAuthLevel)
{
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "ban command denied");
return;
}
}
}
pServer->BanAdd(Addr, Minutes*60, pReason);
}
else if(StrAllnum(pStr))
{
int ClientID = str_toint(pStr);
if(ClientID < 0 || ClientID >= MAX_CLIENTS || pServer->m_aClients[ClientID].m_State == CClient::STATE_EMPTY)
{
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "invalid client id");
return;
}
else if(pServer->m_RconClientID == ClientID)
{
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "you can't ban yourself");
return;
}
else if(pServer->m_aClients[ClientID].m_Authed > pServer->m_RconAuthLevel)
{
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "ban command denied");
return;
}
Addr = pServer->m_NetServer.ClientAddr(ClientID);
pServer->BanAdd(Addr, Minutes*60, pReason);
}
else
{
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "invalid network address to ban");
return;
}
}
void CServer::ConUnban(IConsole::IResult *pResult, void *pUser)
{
NETADDR Addr;
CServer *pServer = (CServer *)pUser;
const char *pStr = pResult->GetString(0);
if(net_addr_from_str(&Addr, pStr) == 0 && !pServer->BanRemove(Addr))
{
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "unbanned %s", aAddrStr);
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
}
else if(StrAllnum(pStr))
{
int BanIndex = str_toint(pStr);
CNetServer::CBanInfo Info;
if(BanIndex < 0 || !pServer->m_NetServer.BanGet(BanIndex, &Info))
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "invalid ban index");
else if(!pServer->BanRemove(Info.m_Addr))
{
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&Info.m_Addr, aAddrStr, sizeof(aAddrStr));
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "unbanned %s", aAddrStr);
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
}
}
else
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "invalid network address");
}
void CServer::ConUnbanAll(IConsole::IResult *pResult, void *pUser)
{
CServer *pServer = (CServer *)pUser;
if(!pServer->BanRemoveAll())
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", "unbanned all");
}
void CServer::ConBans(IConsole::IResult *pResult, void *pUser)
{
unsigned Now = time_timestamp();
char aBuf[1024];
char aAddrStr[NETADDR_MAXSTRSIZE];
CServer* pServer = (CServer *)pUser;
int Num = pServer->m_NetServer.BanNum();
for(int i = 0; i < Num; i++)
{
CNetServer::CBanInfo Info;
pServer->m_NetServer.BanGet(i, &Info);
NETADDR Addr = Info.m_Addr;
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
if(Info.m_Expires == -1)
{
str_format(aBuf, sizeof(aBuf), "#%i %s for life", i, aAddrStr);
}
else
{
unsigned t = Info.m_Expires - Now;
str_format(aBuf, sizeof(aBuf), "#%i %s for %d minutes and %d seconds", i, aAddrStr, t/60, t%60);
}
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
}
str_format(aBuf, sizeof(aBuf), "%d ban(s)", Num);
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
}
void CServer::ConStatus(IConsole::IResult *pResult, void *pUser)
{
int i;
NETADDR Addr;
char aBuf[1024];
char aAddrStr[NETADDR_MAXSTRSIZE];
CServer* pServer = (CServer *)pUser;
CServer* pThis = static_cast<CServer *>(pUser);
for(i = 0; i < MAX_CLIENTS; i++)
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(pServer->m_aClients[i].m_State != CClient::STATE_EMPTY)
if(pThis->m_aClients[i].m_State != CClient::STATE_EMPTY)
{
Addr = pServer->m_NetServer.ClientAddr(i);
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
if(pServer->m_aClients[i].m_State == CClient::STATE_INGAME)
net_addr_str(pThis->m_NetServer.ClientAddr(i), aAddrStr, sizeof(aAddrStr), true);
if(pThis->m_aClients[i].m_State == CClient::STATE_INGAME)
str_format(aBuf, sizeof(aBuf), "id=%d addr=%s name='%s' score=%d", i, aAddrStr,
pServer->m_aClients[i].m_aName, pServer->m_aClients[i].m_Score);
pThis->m_aClients[i].m_aName, pThis->m_aClients[i].m_Score);
else
str_format(aBuf, sizeof(aBuf), "id=%d addr=%s connecting", i, aAddrStr);
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "Server", aBuf);
}
}
}
@ -1653,6 +1593,27 @@ void CServer::ConMapReload(IConsole::IResult *pResult, void *pUser)
((CServer *)pUser)->m_MapReload = 1;
}
void CServer::ConLogout(IConsole::IResult *pResult, void *pUser)
{
CServer *pServer = (CServer *)pUser;
if(pServer->m_RconClientID >= 0 && pServer->m_RconClientID < MAX_CLIENTS &&
pServer->m_aClients[pServer->m_RconClientID].m_State != CServer::CClient::STATE_EMPTY)
{
CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS);
Msg.AddInt(0); //authed
Msg.AddInt(0); //cmdlist
pServer->SendMsgEx(&Msg, MSGFLAG_VITAL, pServer->m_RconClientID, true);
pServer->m_aClients[pServer->m_RconClientID].m_Authed = AUTHED_NO;
pServer->m_aClients[pServer->m_RconClientID].m_pRconCmdToSend = 0;
pServer->SendRconLine(pServer->m_RconClientID, "Logout successful.");
char aBuf[32];
str_format(aBuf, sizeof(aBuf), "ClientID=%d logged out", pServer->m_RconClientID);
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
}
}
void CServer::ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
{
pfnCallback(pResult, pCallbackUserData);
@ -1711,12 +1672,9 @@ void CServer::RegisterCommands()
m_pConsole = Kernel()->RequestInterface<IConsole>();
Console()->Register("kick", "i?r", CFGFLAG_SERVER, ConKick, this, "Kick player with specified id for any reason");
Console()->Register("ban", "s?ir", CFGFLAG_SERVER|CFGFLAG_STORE, ConBan, this, "Ban player with ip/id for x minutes for any reason");
Console()->Register("unban", "s", CFGFLAG_SERVER|CFGFLAG_STORE, ConUnban, this, "Unban ip");
Console()->Register("unban_all", "", CFGFLAG_SERVER|CFGFLAG_STORE, ConUnbanAll, this, "Clear all bans");
Console()->Register("bans", "", CFGFLAG_SERVER|CFGFLAG_STORE, ConBans, this, "Show banlist");
Console()->Register("status", "", CFGFLAG_SERVER, ConStatus, this, "List players");
Console()->Register("shutdown", "", CFGFLAG_SERVER, ConShutdown, this, "Shut down");
Console()->Register("logout", "", CFGFLAG_SERVER, ConLogout, this, "Logout of rcon");
Console()->Register("record", "?s", CFGFLAG_SERVER|CFGFLAG_STORE, ConRecord, this, "Record to a file");
Console()->Register("stoprecord", "", CFGFLAG_SERVER, ConStopRecord, this, "Stop recording");
@ -1782,7 +1740,7 @@ int main(int argc, const char **argv) // ignore_convention
IEngine *pEngine = CreateEngine("Teeworlds");
IEngineMap *pEngineMap = CreateEngineMap();
IGameServer *pGameServer = CreateGameServer();
IConsole *pConsole = CreateConsole(CFGFLAG_SERVER);
IConsole *pConsole = CreateConsole(CFGFLAG_SERVER|CFGFLAG_ECON);
IEngineMasterServer *pEngineMasterServer = CreateEngineMasterServer();
IStorage *pStorage = CreateStorage("Teeworlds", argc, argv); // ignore_convention
IConfig *pConfig = CreateConfig();
@ -1848,8 +1806,10 @@ int main(int argc, const char **argv) // ignore_convention
void CServer::GetClientAddr(int ClientID, NETADDR *pAddr)
{
if(ClientID >= 0 && ClientID < MAX_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_INGAME)
*pAddr = m_NetServer.ClientAddr(ClientID);
if(ClientID >= 0 && ClientID < MAX_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_INGAME) {
NETADDR temp = *m_NetServer.ClientAddr(ClientID);
pAddr = &temp;
}
}
char *CServer::GetAnnouncementLine(char const *pFileName)
@ -1913,7 +1873,7 @@ void CServer::ConBanmasters(IConsole::IResult *pResult, void *pUser)
for(int i = 0; i < NumBanmasters; i++)
{
NETADDR *pBanmaster = pServer->m_NetServer.BanmasterGet(i);
net_addr_str(pBanmaster, aIpString, sizeof(aIpString));
net_addr_str(pBanmaster, aIpString, sizeof(aIpString), false);
str_format(aBuf, sizeof(aBuf), "%d: %s", i, aIpString);
pServer->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server/banmaster", aBuf);
}

View file

@ -15,6 +15,7 @@
#include <base/math.h>
#include <engine/shared/mapchecker.h>
#include <engine/shared/econ.h>
#include <engine/shared/netban.h>
class CSnapIDPool
{
@ -50,6 +51,25 @@ public:
void FreeID(int ID);
};
class CServerBan : public CNetBan
{
class CServer *m_pServer;
template<class T> int BanExt(T *pBanPool, const typename T::CDataType *pData, int Seconds, const char *pReason);
public:
class CServer *Server() const { return m_pServer; }
void Init(class IConsole *pConsole, class IStorage *pStorage, class CServer* pServer);
int BanAddr(const NETADDR *pAddr, int Seconds, const char *pReason);
int BanRange(const CNetRange *pRange, int Seconds, const char *pReason);
static void ConBanExt(class IConsole::IResult *pResult, void *pUser);
};
class CServer : public IServer
{
class IGameServer *m_pGameServer;
@ -116,10 +136,6 @@ public:
const IConsole::CCommandInfo *m_pRconCmdToSend;
void Reset();
// DDRace
NETADDR m_Addr;
};
CClient m_aClients[MAX_CLIENTS];
@ -129,6 +145,7 @@ public:
CSnapIDPool m_IDPool;
CNetServer m_NetServer;
CEcon m_Econ;
CServerBan m_ServerBan;
IEngineMap *m_pMap;
@ -171,6 +188,7 @@ public:
int Init();
void SetRconCID(int ClientID);
bool IsAuthed(int ClientID);
int GetClientInfo(int ClientID, CClientInfo *pInfo);
void GetClientAddr(int ClientID, char *pAddrStr, int Size);
@ -199,13 +217,9 @@ public:
void ProcessClientPacket(CNetChunk *pPacket);
void SendServerInfo(NETADDR *pAddr, int Token);
void SendServerInfo(const NETADDR *pAddr, int Token);
void UpdateServerInfo();
int BanAdd(NETADDR Addr, int Seconds, const char *pReason);
int BanRemove(NETADDR Addr);
int BanRemoveAll();
void PumpNetwork();
char *GetMapName();
@ -215,15 +229,12 @@ public:
int Run();
static void ConKick(IConsole::IResult *pResult, void *pUser);
static void ConBan(IConsole::IResult *pResult, void *pUser);
static void ConUnban(IConsole::IResult *pResult, void *pUser);
static void ConUnbanAll(IConsole::IResult *pResult, void *pUser);
static void ConBans(IConsole::IResult *pResult, void *pUser);
static void ConStatus(IConsole::IResult *pResult, void *pUser);
static void ConStatus(IConsole::IResult *pResult, void *pUser);
static void ConShutdown(IConsole::IResult *pResult, void *pUser);
static void ConRecord(IConsole::IResult *pResult, void *pUser);
static void ConStopRecord(IConsole::IResult *pResult, void *pUser);
static void ConMapReload(IConsole::IResult *pResult, void *pUser);
static void ConLogout(IConsole::IResult *pResult, void *pUser);
static void ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainMaxclientsperipUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConchainModCommandUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);

View file

@ -111,13 +111,8 @@ public:
{
if(!m_ConfigFile)
return;
#if defined(CONF_FAMILY_WINDOWS)
static const char Newline[] = "\r\n";
#else
static const char Newline[] = "\n";
#endif
io_write(m_ConfigFile, pLine, str_length(pLine));
io_write(m_ConfigFile, Newline, sizeof(Newline)-1);
io_write_newline(m_ConfigFile);
}
};

View file

@ -21,11 +21,11 @@ enum
CFGFLAG_SERVER=4,
CFGFLAG_STORE=8,
CFGFLAG_MASTER=16,
CFGFLAG_ECON=32,
// DDRace
CMDFLAG_TEST=32,
CFGFLAG_CHAT = 64
CMDFLAG_TEST=64,
CFGFLAG_CHAT = 128
};
#endif

View file

@ -89,12 +89,12 @@ MACRO_CONFIG_INT(SvRconBantime, sv_rcon_bantime, 5, 0, 1440, CFGFLAG_SERVER, "Th
MACRO_CONFIG_INT(SvAutoDemoRecord, sv_auto_demo_record, 0, 0, 1, CFGFLAG_SERVER, "Automatically record demos")
MACRO_CONFIG_INT(SvAutoDemoMax, sv_auto_demo_max, 10, 0, 1000, CFGFLAG_SERVER, "Maximum number of automatically recorded demos (0 = no limit)")
MACRO_CONFIG_STR(EcBindaddr, ec_bindaddr, 128, "localhost", CFGFLAG_SERVER, "Address to bind the external console to. Anything but 'localhost' is dangerous")
MACRO_CONFIG_INT(EcPort, ec_port, 0, 0, 0, CFGFLAG_SERVER, "Port to use for the external console")
MACRO_CONFIG_STR(EcPassword, ec_password, 32, "", CFGFLAG_SERVER, "External console password")
MACRO_CONFIG_INT(EcBantime, ec_bantime, 0, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if econ authentication fails. 0 just closes the connection")
MACRO_CONFIG_INT(EcAuthTimeout, ec_auth_timeout, 30, 1, 120, CFGFLAG_SERVER, "Time in seconds before the the econ authentification times out")
MACRO_CONFIG_INT(EcOutputLevel, ec_output_level, 1, 0, 2, CFGFLAG_SERVER, "Adjusts the amount of information in the external console")
MACRO_CONFIG_STR(EcBindaddr, ec_bindaddr, 128, "localhost", CFGFLAG_ECON, "Address to bind the external console to. Anything but 'localhost' is dangerous")
MACRO_CONFIG_INT(EcPort, ec_port, 0, 0, 0, CFGFLAG_ECON, "Port to use for the external console")
MACRO_CONFIG_STR(EcPassword, ec_password, 32, "", CFGFLAG_ECON, "External console password")
MACRO_CONFIG_INT(EcBantime, ec_bantime, 0, 0, 1440, CFGFLAG_ECON, "The time a client gets banned if econ authentication fails. 0 just closes the connection")
MACRO_CONFIG_INT(EcAuthTimeout, ec_auth_timeout, 30, 1, 120, CFGFLAG_ECON, "Time in seconds before the the econ authentification times out")
MACRO_CONFIG_INT(EcOutputLevel, ec_output_level, 1, 0, 2, CFGFLAG_ECON, "Adjusts the amount of information in the external console")
MACRO_CONFIG_INT(Debug, debug, 0, 0, 1, CFGFLAG_CLIENT|CFGFLAG_SERVER, "Debug mode")
MACRO_CONFIG_INT(DbgStress, dbg_stress, 0, 0, 0, CFGFLAG_CLIENT|CFGFLAG_SERVER, "Stress systems")

View file

@ -12,6 +12,8 @@
#include "console.h"
#include "linereader.h"
// todo: rework this
const char *CConsole::CResult::GetString(unsigned Index)
{
if (Index < 0 || Index >= m_NumArgs)
@ -168,7 +170,7 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
char* pVictim = 0;
if (Command != 'v')
pResult->AddArgument(pStr);
pResult->AddArgument(pStr);
else
pVictim = pStr;
@ -361,14 +363,14 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientID)
for (int i = 0; i < MAX_CLIENTS; i++)
{
Result.SetVictim(i);
pCommand->m_pfnCallback(&Result, pCommand->m_pUserData);
pCommand->m_pfnCallback(&Result, pCommand->m_pUserData);
}
}
else
pCommand->m_pfnCallback(&Result, pCommand->m_pUserData);
pCommand->m_pfnCallback(&Result, pCommand->m_pUserData);
}
else
pCommand->m_pfnCallback(&Result, pCommand->m_pUserData);
pCommand->m_pfnCallback(&Result, pCommand->m_pUserData);
if (pCommand->m_Flags&CMDFLAG_TEST)
m_Cheated = true;
@ -425,6 +427,14 @@ void CConsole::ExecuteLine(const char *pStr, int ClientID)
CConsole::ExecuteLineStroked(0, pStr, ClientID); // then release it
}
void CConsole::ExecuteLineFlag(const char *pStr, int FlagMask)
{
int Temp = m_FlagMask;
m_FlagMask = FlagMask;
ExecuteLine(pStr);
m_FlagMask = Temp;
}
void CConsole::ExecuteFile(const char *pFilename, int ClientID)
{
@ -696,7 +706,7 @@ void CConsole::ParseArguments(int NumArgs, const char **ppArguments)
void CConsole::AddCommandSorted(CCommand *pCommand)
{
if(!m_pFirstCommand || str_comp(pCommand->m_pName, m_pFirstCommand->m_pName) < 0)
if(!m_pFirstCommand || str_comp(pCommand->m_pName, m_pFirstCommand->m_pName) <= 0)
{
if(m_pFirstCommand && m_pFirstCommand->m_pNext)
pCommand->m_pNext = m_pFirstCommand;
@ -708,7 +718,7 @@ void CConsole::AddCommandSorted(CCommand *pCommand)
{
for(CCommand *p = m_pFirstCommand; p; p = p->m_pNext)
{
if(!p->m_pNext || str_comp(pCommand->m_pName, p->m_pNext->m_pName) < 0)
if(!p->m_pNext || str_comp(pCommand->m_pName, p->m_pNext->m_pName) <= 0)
{
pCommand->m_pNext = p->m_pNext;
p->m_pNext = pCommand;
@ -721,7 +731,13 @@ void CConsole::AddCommandSorted(CCommand *pCommand)
void CConsole::Register(const char *pName, const char *pParams,
int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp)
{
CCommand *pCommand = new(mem_alloc(sizeof(CCommand), sizeof(void*))) CCommand;
CCommand *pCommand = FindCommand(pName, Flags);
bool DoAdd = false;
if(pCommand == 0)
{
pCommand = new(mem_alloc(sizeof(CCommand), sizeof(void*))) CCommand;
DoAdd = true;
}
pCommand->m_pfnCallback = pfnFunc;
pCommand->m_pUserData = pUser;
@ -732,7 +748,8 @@ void CConsole::Register(const char *pName, const char *pParams,
pCommand->m_Flags = Flags;
pCommand->m_Temp = false;
AddCommandSorted(pCommand);
if(DoAdd)
AddCommandSorted(pCommand);
if(pCommand->m_Flags&CFGFLAG_CHAT)
pCommand->SetAccessLevel(ACCESS_LEVEL_USER);

View file

@ -172,7 +172,7 @@ class CConsole : public IConsole
public:
CConsole(int FlagMask);
virtual const CCommandInfo *FirstCommandInfo(int AccessLevel, int Flagmask) const;
virtual const CCommandInfo *FirstCommandInfo(int AccessLevel, int FlagMask) const;
virtual const CCommandInfo *GetCommandInfo(const char *pName, int FlagMask, bool Temp);
virtual void PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser);
@ -186,6 +186,7 @@ public:
virtual bool LineIsValid(const char *pStr);
virtual void ExecuteLine(const char *pStr, int ClientID = -1);
virtual void ExecuteLineFlag(const char *pStr, int FlagMask);
virtual void ExecuteFile(const char *pFilename, int ClientID = -1);
virtual int RegisterPrintCallback(int OutputLevel, FPrintCallback pfnPrintCallback, void *pUserData);

View file

@ -2,14 +2,15 @@
#include <engine/shared/config.h>
#include "econ.h"
#include "netban.h"
int CEcon::NewClientCallback(int ClientID, void *pUser)
{
CEcon *pThis = (CEcon *)pUser;
NETADDR Addr = pThis->m_NetConsole.ClientAddr(ClientID);
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
net_addr_str(pThis->m_NetConsole.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true);
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "client accepted. cid=%d addr=%s'", ClientID, aAddrStr);
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "econ", aBuf);
@ -26,9 +27,8 @@ int CEcon::DelClientCallback(int ClientID, const char *pReason, void *pUser)
{
CEcon *pThis = (CEcon *)pUser;
NETADDR Addr = pThis->m_NetConsole.ClientAddr(ClientID);
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
net_addr_str(pThis->m_NetConsole.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true);
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "client dropped. cid=%d addr=%s reason='%s'", ClientID, aAddrStr, pReason);
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "econ", aBuf);
@ -52,7 +52,15 @@ void CEcon::ConchainEconOutputLevelUpdate(IConsole::IResult *pResult, void *pUse
}
}
void CEcon::Init(IConsole *pConsole)
void CEcon::ConLogout(IConsole::IResult *pResult, void *pUserData)
{
CEcon *pThis = static_cast<CEcon *>(pUserData);
if(pThis->m_UserClientID >= 0 && pThis->m_UserClientID < NET_MAX_CONSOLE_CLIENTS && pThis->m_aClients[pThis->m_UserClientID].m_State != CClient::STATE_EMPTY)
pThis->m_NetConsole.Drop(pThis->m_UserClientID, "Logout");
}
void CEcon::Init(IConsole *pConsole, CNetBan *pNetBan)
{
m_pConsole = pConsole;
@ -60,6 +68,7 @@ void CEcon::Init(IConsole *pConsole)
m_aClients[i].m_State = CClient::STATE_EMPTY;
m_Ready = false;
m_UserClientID = -1;
if(g_Config.m_EcPort == 0 || g_Config.m_EcPassword[0] == 0)
return;
@ -74,7 +83,7 @@ void CEcon::Init(IConsole *pConsole)
BindAddr.port = g_Config.m_EcPort;
}
if(m_NetConsole.Open(BindAddr, 0))
if(m_NetConsole.Open(BindAddr, pNetBan, 0))
{
m_NetConsole.SetCallbacks(NewClientCallback, DelClientCallback, this);
m_Ready = true;
@ -84,6 +93,8 @@ void CEcon::Init(IConsole *pConsole)
Console()->Chain("ec_output_level", ConchainEconOutputLevelUpdate, this);
m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_EcOutputLevel, SendLineCB, this);
Console()->Register("logout", "", CFGFLAG_ECON, ConLogout, this, "Logout of econ");
}
else
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD,"econ", "couldn't open socket. port might already be in use");
@ -115,18 +126,15 @@ void CEcon::Update()
else
{
m_aClients[ClientID].m_AuthTries++;
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "Wrong password %d/%d.", m_aClients[ClientID].m_AuthTries, MAX_AUTH_TRIES);
m_NetConsole.Send(ClientID, aBuf);
char aMsg[128];
str_format(aMsg, sizeof(aMsg), "Wrong password %d/%d.", m_aClients[ClientID].m_AuthTries, MAX_AUTH_TRIES);
m_NetConsole.Send(ClientID, aMsg);
if(m_aClients[ClientID].m_AuthTries >= MAX_AUTH_TRIES)
{
if(!g_Config.m_EcBantime)
m_NetConsole.Drop(ClientID, "Too many authentication tries");
else
{
NETADDR Addr = m_NetConsole.ClientAddr(ClientID);
m_NetConsole.AddBan(Addr, g_Config.m_EcBantime*60);
}
m_NetConsole.NetBan()->BanAddr(m_NetConsole.ClientAddr(ClientID), g_Config.m_EcBantime*60, "Too many authentication tries");
}
}
}
@ -135,7 +143,9 @@ void CEcon::Update()
char aFormatted[256];
str_format(aFormatted, sizeof(aBuf), "cid=%d cmd='%s'", ClientID, aBuf);
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aFormatted);
m_UserClientID = ClientID;
Console()->ExecuteLine(aBuf);
m_UserClientID = -1;
}
}

View file

@ -3,6 +3,7 @@
#include "network.h"
class CEcon
{
enum
@ -31,9 +32,11 @@ class CEcon
bool m_Ready;
int m_PrintCBIndex;
int m_UserClientID;
static void SendLineCB(const char *pLine, void *pUserData);
static void ConchainEconOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
static void ConLogout(IConsole::IResult *pResult, void *pUserData);
static int NewClientCallback(int ClientID, void *pUser);
static int DelClientCallback(int ClientID, const char *pReason, void *pUser);
@ -41,7 +44,7 @@ class CEcon
public:
IConsole *Console() { return m_pConsole; }
void Init(IConsole *pConsole);
void Init(IConsole *pConsole, class CNetBan *pNetBan);
void Update();
void Send(int ClientID, const char *pLine);
void Shutdown();

View file

@ -192,13 +192,13 @@ public:
{
char aAddrStr[NETADDR_MAXSTRSIZE];
if(m_aMasterServers[i].m_Addr.type != NETTYPE_INVALID)
net_addr_str(&m_aMasterServers[i].m_Addr, aAddrStr, sizeof(aAddrStr));
net_addr_str(&m_aMasterServers[i].m_Addr, aAddrStr, sizeof(aAddrStr), true);
else
aAddrStr[0] = 0;
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "%s %s\n", m_aMasterServers[i].m_aHostname, aAddrStr);
str_format(aBuf, sizeof(aBuf), "%s %s", m_aMasterServers[i].m_aHostname, aAddrStr);
io_write(File, aBuf, str_length(aBuf));
io_write_newline(File);
}
io_close(File);

View file

@ -0,0 +1,615 @@
#include <base/math.h>
#include <engine/console.h>
#include <engine/storage.h>
#include <engine/shared/config.h>
#include "netban.h"
bool CNetBan::StrAllnum(const char *pStr)
{
while(*pStr)
{
if(!(*pStr >= '0' && *pStr <= '9'))
return false;
pStr++;
}
return true;
}
CNetBan::CNetHash::CNetHash(const NETADDR *pAddr)
{
if(pAddr->type==NETTYPE_IPV4)
m_Hash = (pAddr->ip[0]+pAddr->ip[1]+pAddr->ip[2]+pAddr->ip[3])&0xFF;
else
m_Hash = (pAddr->ip[0]+pAddr->ip[1]+pAddr->ip[2]+pAddr->ip[3]+pAddr->ip[4]+pAddr->ip[5]+pAddr->ip[6]+pAddr->ip[7]+
pAddr->ip[8]+pAddr->ip[9]+pAddr->ip[10]+pAddr->ip[11]+pAddr->ip[12]+pAddr->ip[13]+pAddr->ip[14]+pAddr->ip[15])&0xFF;
m_HashIndex = 0;
}
CNetBan::CNetHash::CNetHash(const CNetRange *pRange)
{
m_Hash = 0;
m_HashIndex = 0;
for(int i = 0; pRange->m_LB.ip[i] == pRange->m_UB.ip[i]; ++i)
{
m_Hash += pRange->m_LB.ip[i];
++m_HashIndex;
}
m_Hash &= 0xFF;
}
int CNetBan::CNetHash::MakeHashArray(const NETADDR *pAddr, CNetHash aHash[17])
{
int Length = pAddr->type==NETTYPE_IPV4 ? 4 : 16;
aHash[0].m_Hash = 0;
aHash[0].m_HashIndex = 0;
for(int i = 1, Sum = 0; i <= Length; ++i)
{
Sum += pAddr->ip[i-1];
aHash[i].m_Hash = Sum&0xFF;
aHash[i].m_HashIndex = i%Length;
}
return Length;
}
template<class T, int HashCount>
typename CNetBan::CBan<T> *CNetBan::CBanPool<T, HashCount>::Add(const T *pData, const CBanInfo *pInfo, const CNetHash *pNetHash)
{
if(!m_pFirstFree)
return 0;
// create new ban
CBan<T> *pBan = m_pFirstFree;
pBan->m_Data = *pData;
pBan->m_Info = *pInfo;
pBan->m_NetHash = *pNetHash;
if(pBan->m_pNext)
pBan->m_pNext->m_pPrev = pBan->m_pPrev;
if(pBan->m_pPrev)
pBan->m_pPrev->m_pNext = pBan->m_pNext;
else
m_pFirstFree = pBan->m_pNext;
// add it to the hash list
if(m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash])
m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash]->m_pHashPrev = pBan;
pBan->m_pHashPrev = 0;
pBan->m_pHashNext = m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash];
m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash] = pBan;
// insert it into the used list
if(m_pFirstUsed)
{
for(CBan<T> *p = m_pFirstUsed; ; p = p->m_pNext)
{
if(p->m_Info.m_Expires == CBanInfo::EXPIRES_NEVER || (pInfo->m_Expires != CBanInfo::EXPIRES_NEVER && pInfo->m_Expires <= p->m_Info.m_Expires))
{
// insert before
pBan->m_pNext = p;
pBan->m_pPrev = p->m_pPrev;
if(p->m_pPrev)
p->m_pPrev->m_pNext = pBan;
else
m_pFirstUsed = pBan;
p->m_pPrev = pBan;
break;
}
if(!p->m_pNext)
{
// last entry
p->m_pNext = pBan;
pBan->m_pPrev = p;
pBan->m_pNext = 0;
break;
}
}
}
else
{
m_pFirstUsed = pBan;
pBan->m_pNext = pBan->m_pPrev = 0;
}
// update ban count
++m_CountUsed;
return pBan;
}
template<class T, int HashCount>
int CNetBan::CBanPool<T, HashCount>::Remove(CBan<T> *pBan)
{
if(pBan == 0)
return -1;
// remove from hash list
if(pBan->m_pHashNext)
pBan->m_pHashNext->m_pHashPrev = pBan->m_pHashPrev;
if(pBan->m_pHashPrev)
pBan->m_pHashPrev->m_pHashNext = pBan->m_pHashNext;
else
m_paaHashList[pBan->m_NetHash.m_HashIndex][pBan->m_NetHash.m_Hash] = pBan->m_pHashNext;
pBan->m_pHashNext = pBan->m_pHashPrev = 0;
// remove from used list
if(pBan->m_pNext)
pBan->m_pNext->m_pPrev = pBan->m_pPrev;
if(pBan->m_pPrev)
pBan->m_pPrev->m_pNext = pBan->m_pNext;
else
m_pFirstUsed = pBan->m_pNext;
// add to recycle list
if(m_pFirstFree)
m_pFirstFree->m_pPrev = pBan;
pBan->m_pPrev = 0;
pBan->m_pNext = m_pFirstFree;
m_pFirstFree = pBan;
// update ban count
--m_CountUsed;
return 0;
}
template<class T, int HashCount>
void CNetBan::CBanPool<T, HashCount>::Update(CBan<CDataType> *pBan, const CBanInfo *pInfo)
{
pBan->m_Info = *pInfo;
// remove from used list
if(pBan->m_pNext)
pBan->m_pNext->m_pPrev = pBan->m_pPrev;
if(pBan->m_pPrev)
pBan->m_pPrev->m_pNext = pBan->m_pNext;
else
m_pFirstUsed = pBan->m_pNext;
// insert it into the used list
if(m_pFirstUsed)
{
for(CBan<T> *p = m_pFirstUsed; ; p = p->m_pNext)
{
if(p->m_Info.m_Expires == CBanInfo::EXPIRES_NEVER || (pInfo->m_Expires != CBanInfo::EXPIRES_NEVER && pInfo->m_Expires <= p->m_Info.m_Expires))
{
// insert before
pBan->m_pNext = p;
pBan->m_pPrev = p->m_pPrev;
if(p->m_pPrev)
p->m_pPrev->m_pNext = pBan;
else
m_pFirstUsed = pBan;
p->m_pPrev = pBan;
break;
}
if(!p->m_pNext)
{
// last entry
p->m_pNext = pBan;
pBan->m_pPrev = p;
pBan->m_pNext = 0;
break;
}
}
}
else
{
m_pFirstUsed = pBan;
pBan->m_pNext = pBan->m_pPrev = 0;
}
}
template<class T, int HashCount>
void CNetBan::CBanPool<T, HashCount>::Reset()
{
mem_zero(m_paaHashList, sizeof(m_paaHashList));
mem_zero(m_aBans, sizeof(m_aBans));
m_pFirstUsed = 0;
m_CountUsed = 0;
for(int i = 1; i < MAX_BANS-1; ++i)
{
m_aBans[i].m_pNext = &m_aBans[i+1];
m_aBans[i].m_pPrev = &m_aBans[i-1];
}
m_aBans[0].m_pNext = &m_aBans[1];
m_aBans[MAX_BANS-1].m_pPrev = &m_aBans[MAX_BANS-2];
m_pFirstFree = &m_aBans[0];
}
template<class T, int HashCount>
typename CNetBan::CBan<T> *CNetBan::CBanPool<T, HashCount>::Find(const T *pData, const CNetHash *pNetHash) const
{
for(CBan<T> *pBan = m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash]; pBan; pBan = pBan->m_pHashNext)
{
if(NetComp(&pBan->m_Data, pData) == 0)
return pBan;
}
return 0;
}
template<class T, int HashCount>
typename CNetBan::CBan<T> *CNetBan::CBanPool<T, HashCount>::Get(int Index) const
{
if(Index < 0 || Index >= Num())
return 0;
for(CNetBan::CBan<T> *pBan = m_pFirstUsed; pBan; pBan = pBan->m_pNext, --Index)
{
if(Index == 0)
return pBan;
}
return 0;
}
template<class T>
void CNetBan::MakeBanInfo(const CBan<T> *pBan, char *pBuf, unsigned BuffSize, int Type) const
{
if(pBan == 0)
{
if(BuffSize > 0)
pBuf[0] = 0;
return;
}
// build type based part
char aBuf[256];
if(Type == MSGTYPE_PLAYER)
str_copy(aBuf, "You have been banned", sizeof(aBuf));
else
{
char aTemp[256];
switch(Type)
{
case MSGTYPE_LIST:
str_format(aBuf, sizeof(aBuf), "%s banned", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break;
case MSGTYPE_BANADD:
str_format(aBuf, sizeof(aBuf), "banned %s", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break;
case MSGTYPE_BANREM:
str_format(aBuf, sizeof(aBuf), "unbanned %s", NetToString(&pBan->m_Data, aTemp, sizeof(aTemp))); break;
default:
aBuf[0] = 0;
}
}
// add info part
if(pBan->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER)
{
int Mins = ((pBan->m_Info.m_Expires-time_timestamp()) + 59) / 60;
if(Mins <= 1)
str_format(pBuf, BuffSize, "%s for 1 minute (%s)", aBuf, pBan->m_Info.m_aReason);
else
str_format(pBuf, BuffSize, "%s for %d minutes (%s)", aBuf, Mins, pBan->m_Info.m_aReason);
}
else
str_format(pBuf, BuffSize, "%s for life (%s)", aBuf, pBan->m_Info.m_aReason);
}
template<class T>
int CNetBan::Ban(T *pBanPool, const typename T::CDataType *pData, int Seconds, const char *pReason)
{
// do not ban localhost
if(NetMatch(pData, &m_LocalhostIPV4) || NetMatch(pData, &m_LocalhostIPV6))
{
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (localhost)");
return -1;
}
int Stamp = Seconds > 0 ? time_timestamp()+Seconds : CBanInfo::EXPIRES_NEVER;
// set up info
CBanInfo Info = {0};
Info.m_Expires = Stamp;
str_copy(Info.m_aReason, pReason, sizeof(Info.m_aReason));
// check if it already exists
CNetHash NetHash(pData);
CBan<typename T::CDataType> *pBan = pBanPool->Find(pData, &NetHash);
if(pBan)
{
// adjust the ban
pBanPool->Update(pBan, &Info);
char aBuf[128];
MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_LIST);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf);
return 1;
}
// add ban and print result
pBan = pBanPool->Add(pData, &Info, &NetHash);
if(pBan)
{
char aBuf[128];
MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_BANADD);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf);
return 0;
}
else
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (full banlist)");
return -1;
}
template<class T>
int CNetBan::Unban(T *pBanPool, const typename T::CDataType *pData)
{
CNetHash NetHash(pData);
CBan<typename T::CDataType> *pBan = pBanPool->Find(pData, &NetHash);
if(pBan)
{
char aBuf[256];
MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_BANREM);
pBanPool->Remove(pBan);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf);
return 0;
}
else
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "unban failed (invalid entry)");
return -1;
}
void CNetBan::Init(IConsole *pConsole, IStorage *pStorage)
{
m_pConsole = pConsole;
m_pStorage = pStorage;
m_BanAddrPool.Reset();
m_BanRangePool.Reset();
net_host_lookup("localhost", &m_LocalhostIPV4, NETTYPE_IPV4);
net_host_lookup("localhost", &m_LocalhostIPV6, NETTYPE_IPV6);
Console()->Register("ban", "s?ir", CFGFLAG_SERVER|CFGFLAG_MASTER|CFGFLAG_STORE, ConBan, this, "Ban ip for x minutes for any reason");
Console()->Register("ban_range", "ss?ir", CFGFLAG_SERVER|CFGFLAG_MASTER|CFGFLAG_STORE, ConBanRange, this, "Ban ip range for x minutes for any reason");
Console()->Register("unban", "s", CFGFLAG_SERVER|CFGFLAG_MASTER|CFGFLAG_STORE, ConUnban, this, "Unban ip/banlist entry");
Console()->Register("unban_range", "ss", CFGFLAG_SERVER|CFGFLAG_MASTER|CFGFLAG_STORE, ConUnbanRange, this, "Unban ip range");
Console()->Register("unban_all", "", CFGFLAG_SERVER|CFGFLAG_MASTER|CFGFLAG_STORE, ConUnbanAll, this, "Unban all entries");
Console()->Register("bans", "", CFGFLAG_SERVER|CFGFLAG_MASTER|CFGFLAG_STORE, ConBans, this, "Show banlist");
Console()->Register("bans_save", "s", CFGFLAG_SERVER|CFGFLAG_MASTER|CFGFLAG_STORE, ConBansSave, this, "Save banlist in a file");
}
void CNetBan::Update()
{
int Now = time_timestamp();
// remove expired bans
char aBuf[256], aNetStr[256];
while(m_BanAddrPool.First() && m_BanAddrPool.First()->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER && m_BanAddrPool.First()->m_Info.m_Expires < Now)
{
str_format(aBuf, sizeof(aBuf), "ban %s expired", NetToString(&m_BanAddrPool.First()->m_Data, aNetStr, sizeof(aNetStr)));
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf);
m_BanAddrPool.Remove(m_BanAddrPool.First());
}
while(m_BanRangePool.First() && m_BanRangePool.First()->m_Info.m_Expires != CBanInfo::EXPIRES_NEVER && m_BanRangePool.First()->m_Info.m_Expires < Now)
{
str_format(aBuf, sizeof(aBuf), "ban %s expired", NetToString(&m_BanRangePool.First()->m_Data, aNetStr, sizeof(aNetStr)));
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf);
m_BanRangePool.Remove(m_BanRangePool.First());
}
}
int CNetBan::BanAddr(const NETADDR *pAddr, int Seconds, const char *pReason)
{
return Ban(&m_BanAddrPool, pAddr, Seconds, pReason);
}
int CNetBan::BanRange(const CNetRange *pRange, int Seconds, const char *pReason)
{
if(pRange->IsValid())
return Ban(&m_BanRangePool, pRange, Seconds, pReason);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (invalid range)");
return -1;
}
int CNetBan::UnbanByAddr(const NETADDR *pAddr)
{
return Unban(&m_BanAddrPool, pAddr);
}
int CNetBan::UnbanByRange(const CNetRange *pRange)
{
if(pRange->IsValid())
return Unban(&m_BanRangePool, pRange);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban failed (invalid range)");
return -1;
}
int CNetBan::UnbanByIndex(int Index)
{
int Result;
char aBuf[256];
CBanAddr *pBan = m_BanAddrPool.Get(Index);
if(pBan)
{
NetToString(&pBan->m_Data, aBuf, sizeof(aBuf));
Result = m_BanAddrPool.Remove(pBan);
}
else
{
CBanRange *pBan = m_BanRangePool.Get(Index-m_BanAddrPool.Num());
if(pBan)
{
NetToString(&pBan->m_Data, aBuf, sizeof(aBuf));
Result = m_BanRangePool.Remove(pBan);
}
else
{
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "unban failed (invalid index)");
return -1;
}
}
char aMsg[256];
str_format(aMsg, sizeof(aMsg), "unbanned index %i (%s)", Index, aBuf);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aMsg);
return Result;
}
bool CNetBan::IsBanned(const NETADDR *pAddr, char *pBuf, unsigned BufferSize) const
{
CNetHash aHash[17];
int Length = CNetHash::MakeHashArray(pAddr, aHash);
// check ban adresses
CBanAddr *pBan = m_BanAddrPool.Find(pAddr, &aHash[Length]);
if(pBan)
{
MakeBanInfo(pBan, pBuf, BufferSize, MSGTYPE_PLAYER);
return true;
}
// check ban ranges
for(int i = Length-1; i >= 0; --i)
{
for(CBanRange *pBan = m_BanRangePool.First(&aHash[i]); pBan; pBan = pBan->m_pHashNext)
{
if(NetMatch(&pBan->m_Data, pAddr, i, Length))
{
MakeBanInfo(pBan, pBuf, BufferSize, MSGTYPE_PLAYER);
return true;
}
}
}
return false;
}
void CNetBan::ConBan(IConsole::IResult *pResult, void *pUser)
{
CNetBan *pThis = static_cast<CNetBan *>(pUser);
const char *pStr = pResult->GetString(0);
int Minutes = pResult->NumArguments()>1 ? clamp(pResult->GetInteger(1), 0, 44640) : 30;
const char *pReason = pResult->NumArguments()>2 ? pResult->GetString(2) : "No reason given";
NETADDR Addr;
if(net_addr_from_str(&Addr, pStr) == 0)
pThis->BanAddr(&Addr, Minutes*60, pReason);
else
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (invalid network address)");
}
void CNetBan::ConBanRange(IConsole::IResult *pResult, void *pUser)
{
CNetBan *pThis = static_cast<CNetBan *>(pUser);
const char *pStr1 = pResult->GetString(0);
const char *pStr2 = pResult->GetString(1);
int Minutes = pResult->NumArguments()>2 ? clamp(pResult->GetInteger(2), 0, 44640) : 30;
const char *pReason = pResult->NumArguments()>3 ? pResult->GetString(3) : "No reason given";
CNetRange Range;
if(net_addr_from_str(&Range.m_LB, pStr1) == 0 && net_addr_from_str(&Range.m_UB, pStr2) == 0)
pThis->BanRange(&Range, Minutes*60, pReason);
else
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "ban error (invalid range)");
}
void CNetBan::ConUnban(IConsole::IResult *pResult, void *pUser)
{
CNetBan *pThis = static_cast<CNetBan *>(pUser);
const char *pStr = pResult->GetString(0);
if(StrAllnum(pStr))
pThis->UnbanByIndex(str_toint(pStr));
else
{
NETADDR Addr;
if(net_addr_from_str(&Addr, pStr) == 0)
pThis->UnbanByAddr(&Addr);
else
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "unban error (invalid network address)");
}
}
void CNetBan::ConUnbanRange(IConsole::IResult *pResult, void *pUser)
{
CNetBan *pThis = static_cast<CNetBan *>(pUser);
const char *pStr1 = pResult->GetString(0);
const char *pStr2 = pResult->GetString(1);
CNetRange Range;
if(net_addr_from_str(&Range.m_LB, pStr1) == 0 && net_addr_from_str(&Range.m_UB, pStr2) == 0)
pThis->UnbanByRange(&Range);
else
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "unban error (invalid range)");
}
void CNetBan::ConUnbanAll(IConsole::IResult *pResult, void *pUser)
{
CNetBan *pThis = static_cast<CNetBan *>(pUser);
pThis->UnbanAll();
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", "unbanned all entries");
}
void CNetBan::ConBans(IConsole::IResult *pResult, void *pUser)
{
CNetBan *pThis = static_cast<CNetBan *>(pUser);
int Count = 0;
char aBuf[256], aMsg[256];
for(CBanAddr *pBan = pThis->m_BanAddrPool.First(); pBan; pBan = pBan->m_pNext)
{
pThis->MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_LIST);
str_format(aMsg, sizeof(aMsg), "#%i %s", Count++, aBuf);
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aMsg);
}
for(CBanRange *pBan = pThis->m_BanRangePool.First(); pBan; pBan = pBan->m_pNext)
{
pThis->MakeBanInfo(pBan, aBuf, sizeof(aBuf), MSGTYPE_LIST);
str_format(aMsg, sizeof(aMsg), "#%i %s", Count++, aBuf);
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aMsg);
}
str_format(aMsg, sizeof(aMsg), "%d %s", Count, Count==1?"ban":"bans");
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aMsg);
}
void CNetBan::ConBansSave(IConsole::IResult *pResult, void *pUser)
{
CNetBan *pThis = static_cast<CNetBan *>(pUser);
char aBuf[256];
IOHANDLE File = pThis->Storage()->OpenFile(pResult->GetString(0), IOFLAG_WRITE, IStorage::TYPE_SAVE);
if(!File)
{
str_format(aBuf, sizeof(aBuf), "failed to save banlist to '%s'", pResult->GetString(0));
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf);
return;
}
int Now = time_timestamp();
char aAddrStr1[NETADDR_MAXSTRSIZE], aAddrStr2[NETADDR_MAXSTRSIZE];
for(CBanAddr *pBan = pThis->m_BanAddrPool.First(); pBan; pBan = pBan->m_pNext)
{
int Min = pBan->m_Info.m_Expires>-1 ? (pBan->m_Info.m_Expires-Now+59)/60 : -1;
net_addr_str(&pBan->m_Data, aAddrStr1, sizeof(aAddrStr1), false);
str_format(aBuf, sizeof(aBuf), "ban_ip %s %i %s", aAddrStr1, Min, pBan->m_Info.m_aReason);
io_write(File, aBuf, str_length(aBuf));
io_write_newline(File);
}
for(CBanRange *pBan = pThis->m_BanRangePool.First(); pBan; pBan = pBan->m_pNext)
{
int Min = pBan->m_Info.m_Expires>-1 ? (pBan->m_Info.m_Expires-Now+59)/60 : -1;
net_addr_str(&pBan->m_Data.m_LB, aAddrStr1, sizeof(aAddrStr1), false);
net_addr_str(&pBan->m_Data.m_UB, aAddrStr2, sizeof(aAddrStr2), false);
str_format(aBuf, sizeof(aBuf), "ban_range %s %i %s", aAddrStr1, aAddrStr2, Min, pBan->m_Info.m_aReason);
io_write(File, aBuf, str_length(aBuf));
io_write_newline(File);
}
io_close(File);
str_format(aBuf, sizeof(aBuf), "saved banlist to '%s'", pResult->GetString(0));
pThis->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "net_ban", aBuf);
}

184
src/engine/shared/netban.h Normal file
View file

@ -0,0 +1,184 @@
#ifndef ENGINE_SHARED_NETBAN_H
#define ENGINE_SHARED_NETBAN_H
#include <base/system.h>
inline int NetComp(const NETADDR *pAddr1, const NETADDR *pAddr2)
{
return mem_comp(pAddr1, pAddr2, pAddr1->type==NETTYPE_IPV4 ? 8 : 20);
}
class CNetRange
{
public:
NETADDR m_LB;
NETADDR m_UB;
bool IsValid() const { return m_LB.type == m_UB.type && NetComp(&m_LB, &m_UB) < 0; }
};
inline int NetComp(const CNetRange *pRange1, const CNetRange *pRange2)
{
return NetComp(&pRange1->m_LB, &pRange2->m_LB) || NetComp(&pRange1->m_UB, &pRange2->m_UB);
}
class CNetBan
{
protected:
bool NetMatch(const NETADDR *pAddr1, const NETADDR *pAddr2) const
{
return NetComp(pAddr1, pAddr2) == 0;
}
bool NetMatch(const CNetRange *pRange, const NETADDR *pAddr, int Start, int Length) const
{
return pRange->m_LB.type == pAddr->type &&
mem_comp(&pRange->m_LB.ip[Start], &pAddr->ip[Start], Length-Start) <= 0 && mem_comp(&pRange->m_UB.ip[Start], &pAddr->ip[Start], Length-Start) >= 0;
}
bool NetMatch(const CNetRange *pRange, const NETADDR *pAddr) const
{
return NetMatch(pRange, pAddr, 0, pRange->m_LB.type==NETTYPE_IPV4 ? 4 : 16);
}
const char *NetToString(const NETADDR *pData, char *pBuffer, unsigned BufferSize) const
{
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(pData, aAddrStr, sizeof(aAddrStr), false);
str_format(pBuffer, BufferSize, "'%s'", aAddrStr);
return pBuffer;
}
const char *NetToString(const CNetRange *pData, char *pBuffer, unsigned BufferSize) const
{
char aAddrStr1[NETADDR_MAXSTRSIZE], aAddrStr2[NETADDR_MAXSTRSIZE];
net_addr_str(&pData->m_LB, aAddrStr1, sizeof(aAddrStr1), false);
net_addr_str(&pData->m_UB, aAddrStr2, sizeof(aAddrStr2), false);
str_format(pBuffer, BufferSize, "'%s' - '%s'", aAddrStr1, aAddrStr2);
return pBuffer;
}
// todo: move?
static bool StrAllnum(const char *pStr);
class CNetHash
{
public:
int m_Hash;
int m_HashIndex; // matching parts for ranges, 0 for addr
CNetHash() {}
CNetHash(const NETADDR *pAddr);
CNetHash(const CNetRange *pRange);
static int MakeHashArray(const NETADDR *pAddr, CNetHash aHash[17]);
};
struct CBanInfo
{
enum
{
EXPIRES_NEVER=-1,
REASON_LENGTH=64,
};
int m_Expires;
char m_aReason[REASON_LENGTH];
};
template<class T> struct CBan
{
T m_Data;
CBanInfo m_Info;
CNetHash m_NetHash;
// hash list
CBan *m_pHashNext;
CBan *m_pHashPrev;
// used or free list
CBan *m_pNext;
CBan *m_pPrev;
};
template<class T, int HashCount> class CBanPool
{
public:
typedef T CDataType;
CBan<CDataType> *Add(const CDataType *pData, const CBanInfo *pInfo, const CNetHash *pNetHash);
int Remove(CBan<CDataType> *pBan);
void Update(CBan<CDataType> *pBan, const CBanInfo *pInfo);
void Reset();
int Num() const { return m_CountUsed; }
bool IsFull() const { return m_CountUsed == MAX_BANS; }
CBan<CDataType> *First() const { return m_pFirstUsed; }
CBan<CDataType> *First(const CNetHash *pNetHash) const { return m_paaHashList[pNetHash->m_HashIndex][pNetHash->m_Hash]; }
CBan<CDataType> *Find(const CDataType *pData, const CNetHash *pNetHash) const;
CBan<CDataType> *Get(int Index) const;
private:
enum
{
MAX_BANS=1024,
};
CBan<CDataType> *m_paaHashList[HashCount][256];
CBan<CDataType> m_aBans[MAX_BANS];
CBan<CDataType> *m_pFirstFree;
CBan<CDataType> *m_pFirstUsed;
int m_CountUsed;
};
typedef CBanPool<NETADDR, 1> CBanAddrPool;
typedef CBanPool<CNetRange, 16> CBanRangePool;
typedef CBan<NETADDR> CBanAddr;
typedef CBan<CNetRange> CBanRange;
template<class T> void MakeBanInfo(const CBan<T> *pBan, char *pBuf, unsigned BuffSize, int Type) const;
template<class T> int Ban(T *pBanPool, const typename T::CDataType *pData, int Seconds, const char *pReason);
template<class T> int Unban(T *pBanPool, const typename T::CDataType *pData);
class IConsole *m_pConsole;
class IStorage *m_pStorage;
CBanAddrPool m_BanAddrPool;
CBanRangePool m_BanRangePool;
NETADDR m_LocalhostIPV4, m_LocalhostIPV6;
public:
enum
{
MSGTYPE_PLAYER=0,
MSGTYPE_LIST,
MSGTYPE_BANADD,
MSGTYPE_BANREM,
};
class IConsole *Console() const { return m_pConsole; }
class IStorage *Storage() const { return m_pStorage; }
virtual ~CNetBan() {}
virtual void Init(class IConsole *pConsole, class IStorage *pStorage);
void Update();
virtual int BanAddr(const NETADDR *pAddr, int Seconds, const char *pReason);
virtual int BanRange(const CNetRange *pRange, int Seconds, const char *pReason);
int UnbanByAddr(const NETADDR *pAddr);
int UnbanByRange(const CNetRange *pRange);
int UnbanByIndex(int Index);
void UnbanAll() { m_BanAddrPool.Reset(); m_BanRangePool.Reset(); }
bool IsBanned(const NETADDR *pAddr, char *pBuf, unsigned BufferSize) const;
static void ConBan(class IConsole::IResult *pResult, void *pUser);
static void ConBanRange(class IConsole::IResult *pResult, void *pUser);
static void ConUnban(class IConsole::IResult *pResult, void *pUser);
static void ConUnbanRange(class IConsole::IResult *pResult, void *pUser);
static void ConUnbanAll(class IConsole::IResult *pResult, void *pUser);
static void ConBans(class IConsole::IResult *pResult, void *pUser);
static void ConBansSave(class IConsole::IResult *pResult, void *pUser);
};
#endif

View file

@ -73,8 +73,6 @@ enum
NET_CTRLMSG_ACCEPT=3,
NET_CTRLMSG_CLOSE=4,
NET_SERVER_MAXBANS=1024,
NET_CONN_BUFFERSIZE=1024*32,
NET_ENUM_TERMINATOR
@ -182,7 +180,7 @@ public:
const char *ErrorString();
void SignalResend();
int State() const { return m_State; }
NETADDR PeerAddress() const { return m_PeerAddr; }
const NETADDR *PeerAddress() const { return &m_PeerAddr; }
void ResetErrorString() { m_ErrorString[0] = 0; }
const char *ErrorString() const { return m_ErrorString; }
@ -214,7 +212,7 @@ public:
void Disconnect(const char *pReason);
int State() const { return m_State; }
NETADDR PeerAddress() const { return m_PeerAddr; }
const NETADDR *PeerAddress() const { return &m_PeerAddr; }
const char *ErrorString() const { return m_aErrorString; }
void Reset();
@ -244,59 +242,29 @@ public:
// server side
class CNetServer
{
public:
struct CBanInfo
{
NETADDR m_Addr;
int m_Expires;
char m_Reason[128];
};
private:
struct CSlot
{
public:
CNetConnection m_Connection;
};
struct CBan
{
public:
CBanInfo m_Info;
// hash list
CBan *m_pHashNext;
CBan *m_pHashPrev;
// used or free list
CBan *m_pNext;
CBan *m_pPrev;
};
NETSOCKET m_Socket;
class CNetBan *m_pNetBan;
CSlot m_aSlots[NET_MAX_CLIENTS];
int m_MaxClients;
int m_MaxClientsPerIP;
CBan *m_aBans[256];
CBan m_BanPool[NET_SERVER_MAXBANS];
CBan *m_BanPool_FirstFree;
CBan *m_BanPool_FirstUsed;
NETFUNC_NEWCLIENT m_pfnNewClient;
NETFUNC_DELCLIENT m_pfnDelClient;
void *m_UserPtr;
CNetRecvUnpacker m_RecvUnpacker;
void BanRemoveByObject(CBan *pBan);
public:
int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
//
bool Open(NETADDR BindAddr, int MaxClients, int MaxClientsPerIP, int Flags);
bool Open(NETADDR BindAddr, class CNetBan *pNetBan, int MaxClients, int MaxClientsPerIP, int Flags);
int Close();
//
@ -307,16 +275,10 @@ public:
//
int Drop(int ClientID, const char *pReason);
// banning
int BanAdd(NETADDR Addr, int Seconds, const char *pReason);
int BanRemove(NETADDR Addr);
int BanRemoveAll();
int BanNum(); // caution, slow
int BanGet(int Index, CBanInfo *pInfo); // caution, slow
// status requests
NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); }
const NETADDR *ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); }
NETSOCKET Socket() const { return m_Socket; }
class CNetBan *NetBan() const { return m_pNetBan; }
int NetType() const { return m_Socket.type; }
int MaxClients() const { return m_MaxClients; }
@ -341,27 +303,13 @@ private:
class CNetConsole
{
enum
{
MAX_BANS=128,
};
int FindBan(NETADDR Addr);
void UpdateBans();
struct CBanEntry
{
NETADDR m_Addr;
int m_Expires;
} m_aBans[MAX_BANS];
int m_NumBans;
struct CSlot
{
CConsoleNetConnection m_Connection;
};
NETSOCKET m_Socket;
class CNetBan *m_pNetBan;
CSlot m_aSlots[NET_MAX_CONSOLE_CLIENTS];
NETFUNC_NEWCLIENT m_pfnNewClient;
@ -374,7 +322,7 @@ public:
void SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser);
//
bool Open(NETADDR BindAddr, int Flags);
bool Open(NETADDR BindAddr, class CNetBan *pNetBan, int Flags);
int Close();
//
@ -386,10 +334,9 @@ public:
int AcceptClient(NETSOCKET Socket, const NETADDR *pAddr);
int Drop(int ClientID, const char *pReason);
bool AddBan(NETADDR Addr, int Seconds);
// status requests
NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); }
const NETADDR *ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); }
class CNetBan *NetBan() const { return m_pNetBan; }
};

View file

@ -1,15 +1,21 @@
/* (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 <base/system.h>
#include <engine/console.h>
#include "netban.h"
#include "network.h"
bool CNetConsole::Open(NETADDR BindAddr, int Flags)
bool CNetConsole::Open(NETADDR BindAddr, CNetBan *pNetBan, int Flags)
{
// zero out the whole structure
mem_zero(this, sizeof(*this));
m_Socket.type = NETTYPE_INVALID;
m_Socket.ipv4sock = -1;
m_Socket.ipv6sock = -1;
m_pNetBan = pNetBan;
// open socket
m_Socket = net_tcp_create(BindAddr);
@ -64,8 +70,7 @@ int CNetConsole::AcceptClient(NETSOCKET Socket, const NETADDR *pAddr)
FreeSlot = i;
if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE)
{
NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();
if(net_addr_comp(pAddr, &PeerAddr) == 0)
if(net_addr_comp(pAddr, m_aSlots[i].m_Connection.PeerAddress()) == 0)
{
str_copy(aError, "only one client per IP allowed", sizeof(aError));
break;
@ -99,26 +104,16 @@ int CNetConsole::Update()
if(net_tcp_accept(m_Socket, &Socket, &Addr) > 0)
{
int Index = FindBan(Addr);
if(Index == -1)
AcceptClient(Socket, &Addr);
else
// check if we just should drop the packet
char aBuf[128];
if(NetBan() && NetBan()->IsBanned(&Addr, aBuf, sizeof(aBuf)))
{
char aBuf[128];
if(m_aBans[Index].m_Expires > -1)
{
int Mins = (m_aBans[Index].m_Expires-time_timestamp()+ 59) / 60;
if(Mins <= 1)
str_format(aBuf, sizeof(aBuf), "You have been banned for 1 minute");
else
str_format(aBuf, sizeof(aBuf), "You have been banned for %d minutes", Mins);
}
else
str_format(aBuf, sizeof(aBuf), "You have been banned for life");
// banned, reply with a message and drop
net_tcp_send(Socket, aBuf, str_length(aBuf));
net_tcp_close(Socket);
}
else
AcceptClient(Socket, &Addr);
}
for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
@ -129,8 +124,6 @@ int CNetConsole::Update()
Drop(i, m_aSlots[i].m_Connection.ErrorString());
}
UpdateBans();
return 0;
}
@ -155,65 +148,3 @@ int CNetConsole::Send(int ClientID, const char *pLine)
else
return -1;
}
int CNetConsole::FindBan(NETADDR Addr)
{
Addr.port = 0;
for(int i = 0; i < m_NumBans; i++)
if(net_addr_comp(&m_aBans[i].m_Addr, &Addr) == 0)
return i;
return -1;
}
bool CNetConsole::AddBan(NETADDR Addr, int Seconds)
{
if(m_NumBans == MAX_BANS)
return false;
Addr.port = 0;
int Index = FindBan(Addr);
if(Index == -1)
{
Index = m_NumBans++;
m_aBans[Index].m_Addr = Addr;
}
m_aBans[Index].m_Expires = Seconds>0 ? time_timestamp()+Seconds : -1;
for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
{
if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE)
{
NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();
PeerAddr.port = 0;
if(net_addr_comp(&Addr, &PeerAddr) == 0)
{
char aBuf[128];
if(Seconds>0)
{
int Mins = (Seconds + 59) / 60;
if(Mins <= 1)
str_format(aBuf, sizeof(aBuf), "You have been banned for 1 minute");
else
str_format(aBuf, sizeof(aBuf), "You have been banned for %d minutes", Mins);
}
else
str_format(aBuf, sizeof(aBuf), "You have been banned for life");
Drop(i, aBuf);
}
}
}
return true;
}
void CNetConsole::UpdateBans()
{
int Now = time_timestamp();
for(int i = 0; i < m_NumBans; ++i)
if(m_aBans[i].m_Expires > 0 && m_aBans[i].m_Expires < Now)
{
m_aBans[i] = m_aBans[m_NumBans-1];
--m_NumBans;
break;
}
}

View file

@ -1,34 +1,16 @@
/* (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 <base/system.h>
#include <engine/console.h>
#include "netban.h"
#include "network.h"
#include <banmaster/banmaster.h>
#define MACRO_LIST_LINK_FIRST(Object, First, Prev, Next) \
{ if(First) First->Prev = Object; \
Object->Prev = (struct CBan *)0; \
Object->Next = First; \
First = Object; }
#define MACRO_LIST_LINK_AFTER(Object, After, Prev, Next) \
{ Object->Prev = After; \
Object->Next = After->Next; \
After->Next = Object; \
if(Object->Next) \
Object->Next->Prev = Object; \
}
#define MACRO_LIST_UNLINK(Object, First, Prev, Next) \
{ if(Object->Next) Object->Next->Prev = Object->Prev; \
if(Object->Prev) Object->Prev->Next = Object->Next; \
else First = Object->Next; \
Object->Next = 0; Object->Prev = 0; }
#define MACRO_LIST_FIND(Start, Next, Expression) \
{ while(Start && !(Expression)) Start = Start->Next; }
bool CNetServer::Open(NETADDR BindAddr, int MaxClients, int MaxClientsPerIP, int Flags)
bool CNetServer::Open(NETADDR BindAddr, CNetBan *pNetBan, int MaxClients, int MaxClientsPerIP, int Flags)
{
// zero out the whole structure
mem_zero(this, sizeof(*this));
@ -38,6 +20,8 @@ bool CNetServer::Open(NETADDR BindAddr, int MaxClients, int MaxClientsPerIP, int
if(!m_Socket.type)
return false;
m_pNetBan = pNetBan;
// clamp clients
m_MaxClients = MaxClients;
if(m_MaxClients > NET_MAX_CLIENTS)
@ -50,8 +34,6 @@ bool CNetServer::Open(NETADDR BindAddr, int MaxClients, int MaxClientsPerIP, int
for(int i = 0; i < NET_MAX_CLIENTS; i++)
m_aSlots[i].m_Connection.Init(m_Socket);
BanRemoveAll();
return true;
}
@ -87,182 +69,8 @@ int CNetServer::Drop(int ClientID, const char *pReason)
return 0;
}
int CNetServer::BanGet(int Index, CBanInfo *pInfo)
{
CBan *pBan;
for(pBan = m_BanPool_FirstUsed; pBan && Index; pBan = pBan->m_pNext, Index--)
{}
if(!pBan)
return 0;
*pInfo = pBan->m_Info;
return 1;
}
int CNetServer::BanNum()
{
int Count = 0;
CBan *pBan;
for(pBan = m_BanPool_FirstUsed; pBan; pBan = pBan->m_pNext)
Count++;
return Count;
}
void CNetServer::BanRemoveByObject(CBan *pBan)
{
int IpHash = (pBan->m_Info.m_Addr.ip[0]+pBan->m_Info.m_Addr.ip[1]+pBan->m_Info.m_Addr.ip[2]+pBan->m_Info.m_Addr.ip[3]+
pBan->m_Info.m_Addr.ip[4]+pBan->m_Info.m_Addr.ip[5]+pBan->m_Info.m_Addr.ip[6]+pBan->m_Info.m_Addr.ip[7]+
pBan->m_Info.m_Addr.ip[8]+pBan->m_Info.m_Addr.ip[9]+pBan->m_Info.m_Addr.ip[10]+pBan->m_Info.m_Addr.ip[11]+
pBan->m_Info.m_Addr.ip[12]+pBan->m_Info.m_Addr.ip[13]+pBan->m_Info.m_Addr.ip[14]+pBan->m_Info.m_Addr.ip[15])&0xff;
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&pBan->m_Info.m_Addr, aAddrStr, sizeof(aAddrStr));
dbg_msg("netserver", "removing ban on %s", aAddrStr);
MACRO_LIST_UNLINK(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext);
MACRO_LIST_UNLINK(pBan, m_aBans[IpHash], m_pHashPrev, m_pHashNext);
MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstFree, m_pPrev, m_pNext);
}
int CNetServer::BanRemove(NETADDR Addr)
{
int IpHash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3]+Addr.ip[4]+Addr.ip[5]+Addr.ip[6]+Addr.ip[7]+
Addr.ip[8]+Addr.ip[9]+Addr.ip[10]+Addr.ip[11]+Addr.ip[12]+Addr.ip[13]+Addr.ip[14]+Addr.ip[15])&0xff;
CBan *pBan = m_aBans[IpHash];
MACRO_LIST_FIND(pBan, m_pHashNext, net_addr_comp(&pBan->m_Info.m_Addr, &Addr) == 0);
if(pBan)
{
BanRemoveByObject(pBan);
return 0;
}
return -1;
}
int CNetServer::BanRemoveAll()
{
// clear bans memory
mem_zero(m_aBans, sizeof(m_aBans));
mem_zero(m_BanPool, sizeof(m_BanPool));
m_BanPool_FirstFree = 0;
m_BanPool_FirstUsed = 0;
// setup all pointers for bans
for(int i = 1; i < NET_SERVER_MAXBANS-1; i++)
{
m_BanPool[i].m_pNext = &m_BanPool[i+1];
m_BanPool[i].m_pPrev = &m_BanPool[i-1];
}
m_BanPool[0].m_pNext = &m_BanPool[1];
m_BanPool[NET_SERVER_MAXBANS-1].m_pPrev = &m_BanPool[NET_SERVER_MAXBANS-2];
m_BanPool_FirstFree = &m_BanPool[0];
return 0;
}
int CNetServer::BanAdd(NETADDR Addr, int Seconds, const char *pReason)
{
int IpHash = (Addr.ip[0]+Addr.ip[1]+Addr.ip[2]+Addr.ip[3]+Addr.ip[4]+Addr.ip[5]+Addr.ip[6]+Addr.ip[7]+
Addr.ip[8]+Addr.ip[9]+Addr.ip[10]+Addr.ip[11]+Addr.ip[12]+Addr.ip[13]+Addr.ip[14]+Addr.ip[15])&0xff;
int Stamp = -1;
CBan *pBan;
// remove the port
Addr.port = 0;
if(Seconds)
Stamp = time_timestamp() + Seconds;
// search to remove it if it already exists
pBan = m_aBans[IpHash];
MACRO_LIST_FIND(pBan, m_pHashNext, net_addr_comp(&pBan->m_Info.m_Addr, &Addr) == 0);
if(pBan)
BanRemoveByObject(pBan);
if(!m_BanPool_FirstFree)
return -1;
// fetch and clear the new ban
pBan = m_BanPool_FirstFree;
MACRO_LIST_UNLINK(pBan, m_BanPool_FirstFree, m_pPrev, m_pNext);
// setup the ban info
pBan->m_Info.m_Expires = Stamp;
pBan->m_Info.m_Addr = Addr;
str_copy(pBan->m_Info.m_Reason, pReason, sizeof(pBan->m_Info.m_Reason));
// add it to the ban hash
MACRO_LIST_LINK_FIRST(pBan, m_aBans[IpHash], m_pHashPrev, m_pHashNext);
// insert it into the used list
{
if(m_BanPool_FirstUsed)
{
CBan *pInsertAfter = m_BanPool_FirstUsed;
MACRO_LIST_FIND(pInsertAfter, m_pNext, Stamp < pInsertAfter->m_Info.m_Expires);
if(pInsertAfter && Stamp != -1)
pInsertAfter = pInsertAfter->m_pPrev;
else
{
// add to last
if (m_BanPool_FirstUsed->m_Info.m_Expires == -1)
pInsertAfter = 0;
else
{
pInsertAfter = m_BanPool_FirstUsed;
while(pInsertAfter->m_pNext && pInsertAfter->m_pNext->m_Info.m_Expires != -1)
pInsertAfter = pInsertAfter->m_pNext;
}
}
if(pInsertAfter)
{
MACRO_LIST_LINK_AFTER(pBan, pInsertAfter, m_pPrev, m_pNext);
}
else
{
MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext);
}
}
else
{
MACRO_LIST_LINK_FIRST(pBan, m_BanPool_FirstUsed, m_pPrev, m_pNext);
}
}
// drop banned clients
{
char Buf[128];
NETADDR BanAddr;
if(Stamp > -1)
{
int Mins = (Seconds + 59) / 60;
if(Mins <= 1)
str_format(Buf, sizeof(Buf), "You have been banned for 1 minute (%s)", pReason);
else
str_format(Buf, sizeof(Buf), "You have been banned for %d minutes (%s)", Mins, pReason);
}
else
str_format(Buf, sizeof(Buf), "You have been banned for life (%s)", pReason);
for(int i = 0; i < MaxClients(); i++)
{
BanAddr = m_aSlots[i].m_Connection.PeerAddress();
BanAddr.port = 0;
if(net_addr_comp(&Addr, &BanAddr) == 0)
Drop(i, Buf);
}
}
return 0;
}
int CNetServer::Update()
{
int Now = time_timestamp();
for(int i = 0; i < MaxClients(); i++)
{
m_aSlots[i].m_Connection.Update();
@ -270,13 +78,6 @@ int CNetServer::Update()
Drop(i, m_aSlots[i].m_Connection.ErrorString());
}
// remove expired bans
while(m_BanPool_FirstUsed && m_BanPool_FirstUsed->m_Info.m_Expires > -1 && m_BanPool_FirstUsed->m_Info.m_Expires < Now)
{
CBan *pBan = m_BanPool_FirstUsed;
BanRemoveByObject(pBan);
}
return 0;
}
@ -285,8 +86,6 @@ int CNetServer::Update()
*/
int CNetServer::Recv(CNetChunk *pChunk)
{
unsigned Now = time_timestamp();
while(1)
{
NETADDR Addr;
@ -304,36 +103,12 @@ int CNetServer::Recv(CNetChunk *pChunk)
if(CNetBase::UnpackPacket(m_RecvUnpacker.m_aBuffer, Bytes, &m_RecvUnpacker.m_Data) == 0)
{
CBan *pBan = 0;
NETADDR BanAddr = Addr;
int IpHash = (BanAddr.ip[0]+BanAddr.ip[1]+BanAddr.ip[2]+BanAddr.ip[3]+BanAddr.ip[4]+BanAddr.ip[5]+BanAddr.ip[6]+BanAddr.ip[7]+
BanAddr.ip[8]+BanAddr.ip[9]+BanAddr.ip[10]+BanAddr.ip[11]+BanAddr.ip[12]+BanAddr.ip[13]+BanAddr.ip[14]+BanAddr.ip[15])&0xff;
int Found = 0;
BanAddr.port = 0;
// search a ban
for(pBan = m_aBans[IpHash]; pBan; pBan = pBan->m_pHashNext)
{
if(net_addr_comp(&pBan->m_Info.m_Addr, &BanAddr) == 0)
break;
}
// check if we just should drop the packet
if(pBan)
char aBuf[128];
if(NetBan() && NetBan()->IsBanned(&Addr, aBuf, sizeof(aBuf)))
{
// banned, reply with a message
char BanStr[128];
if(pBan->m_Info.m_Expires > -1)
{
int Mins = ((pBan->m_Info.m_Expires - Now)+59)/60;
if(Mins <= 1)
str_format(BanStr, sizeof(BanStr), "Banned for 1 minute (%s)", pBan->m_Info.m_Reason);
else
str_format(BanStr, sizeof(BanStr), "Banned for %d minutes (%s)", Mins, pBan->m_Info.m_Reason);
}
else
str_format(BanStr, sizeof(BanStr), "Banned for life (%s)", pBan->m_Info.m_Reason);
CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, BanStr, str_length(BanStr)+1);
CNetBase::SendControlMsg(m_Socket, &Addr, 0, NET_CTRLMSG_CLOSE, aBuf, str_length(aBuf)+1);
continue;
}
@ -351,16 +126,15 @@ int CNetServer::Recv(CNetChunk *pChunk)
// TODO: check size here
if(m_RecvUnpacker.m_Data.m_Flags&NET_PACKETFLAG_CONTROL && m_RecvUnpacker.m_Data.m_aChunkData[0] == NET_CTRLMSG_CONNECT)
{
Found = 0;
bool Found = false;
// check if we already got this client
for(int i = 0; i < MaxClients(); i++)
{
NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();
if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE &&
net_addr_comp(&PeerAddr, &Addr) == 0)
net_addr_comp(m_aSlots[i].m_Connection.PeerAddress(), &Addr) == 0)
{
Found = 1; // silent ignore.. we got this client already
Found = true; // silent ignore.. we got this client already
break;
}
}
@ -371,7 +145,7 @@ int CNetServer::Recv(CNetChunk *pChunk)
CNetChunk Packet;
char aBuffer[sizeof(BANMASTER_IPCHECK) + NETADDR_MAXSTRSIZE];
mem_copy(aBuffer, BANMASTER_IPCHECK, sizeof(BANMASTER_IPCHECK));
net_addr_str(&Addr, aBuffer + sizeof(BANMASTER_IPCHECK), sizeof(aBuffer) - sizeof(BANMASTER_IPCHECK));
net_addr_str(&Addr, aBuffer + sizeof(BANMASTER_IPCHECK), sizeof(aBuffer) - sizeof(BANMASTER_IPCHECK), false);
Packet.m_ClientID = -1;
Packet.m_Flags = NETSENDFLAG_CONNLESS;
@ -393,7 +167,7 @@ int CNetServer::Recv(CNetChunk *pChunk)
if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE)
continue;
OtherAddr = m_aSlots[i].m_Connection.PeerAddress();
OtherAddr = *m_aSlots[i].m_Connection.PeerAddress();
OtherAddr.port = 0;
if(!net_addr_comp(&ThisAddr, &OtherAddr))
{
@ -411,7 +185,7 @@ int CNetServer::Recv(CNetChunk *pChunk)
{
if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE)
{
Found = 1;
Found = true;
m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr);
if(m_pfnNewClient)
m_pfnNewClient(i, m_UserPtr);
@ -431,8 +205,7 @@ int CNetServer::Recv(CNetChunk *pChunk)
// normal packet, find matching slot
for(int i = 0; i < MaxClients(); i++)
{
NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();
if(net_addr_comp(&PeerAddr, &Addr) == 0)
if(net_addr_comp(m_aSlots[i].m_Connection.PeerAddress(), &Addr) == 0)
{
if(m_aSlots[i].m_Connection.Feed(&m_RecvUnpacker.m_Data, &Addr))
{

View file

@ -615,16 +615,10 @@ void CGameConsole::Dump(int Type)
IOHANDLE io = Storage()->OpenFile(aFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
if(io)
{
#if defined(CONF_FAMILY_WINDOWS)
static const char Newline[] = "\r\n";
#else
static const char Newline[] = "\n";
#endif
for(CInstance::CBacklogEntry *pEntry = pConsole->m_Backlog.First(); pEntry; pEntry = pConsole->m_Backlog.Next(pEntry))
{
io_write(io, pEntry->m_aText, str_length(pEntry->m_aText));
io_write(io, Newline, sizeof(Newline)-1);
io_write_newline(io);
}
io_close(io);
}

View file

@ -212,16 +212,11 @@ void CMapLayers::OnRender()
IOHANDLE File = Storage()->OpenFile(aFilename, IOFLAG_WRITE, IStorage::TYPE_SAVE);
if(File)
{
#if defined(CONF_FAMILY_WINDOWS)
static const char Newline[] = "\r\n";
#else
static const char Newline[] = "\n";
#endif
for(int y = 0; y < pTMap->m_Height; y++)
{
for(int x = 0; x < pTMap->m_Width; x++)
io_write(File, &(pTiles[y*pTMap->m_Width + x].m_Index), sizeof(pTiles[y*pTMap->m_Width + x].m_Index));
io_write(File, Newline, sizeof(Newline)-1);
io_write_newline(File);
}
io_close(File);
}

View file

@ -207,6 +207,8 @@ void CGameClient::OnConsoleInit()
Console()->Register("force_vote", "ss?r", CFGFLAG_SERVER, 0, 0, "Force a voting option");
Console()->Register("clear_votes", "", CFGFLAG_SERVER, 0, 0, "Clears the voting options");
Console()->Register("vote", "r", CFGFLAG_SERVER, 0, 0, "Force a vote to yes/no");
Console()->Register("swap_teams", "", CFGFLAG_SERVER, 0, 0, "Swap the current teams");
Console()->Register("shuffle_teams", "", CFGFLAG_SERVER, 0, 0, "Shuffle the current teams");
// propagate pointers

View file

@ -389,7 +389,7 @@ void CGameContext::ConUnmute(IConsole::IResult *pResult, void *pUserData)
pSelf->m_NumMutes--;
pSelf->m_aMutes[Victim] = pSelf->m_aMutes[pSelf->m_NumMutes];
net_addr_str(&pSelf->m_aMutes[Victim].m_Addr, aIpBuf, sizeof(aIpBuf));
net_addr_str(&pSelf->m_aMutes[Victim].m_Addr, aIpBuf, sizeof(aIpBuf), false);
str_format(aBuf, sizeof(aBuf), "Unmuted %s", aIpBuf);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mutes", aBuf);
}
@ -404,7 +404,7 @@ void CGameContext::ConMutes(IConsole::IResult *pResult, void *pUserData)
"Active mutes:");
for (int i = 0; i < pSelf->m_NumMutes; i++)
{
net_addr_str(&pSelf->m_aMutes[i].m_Addr, aIpBuf, sizeof(aIpBuf));
net_addr_str(&pSelf->m_aMutes[i].m_Addr, aIpBuf, sizeof(aIpBuf), false);
str_format(
aBuf,
sizeof aBuf,

View file

@ -230,7 +230,15 @@ void CGameContext::CreateSoundGlobal(int Sound, int Target)
CNetMsg_Sv_SoundGlobal Msg;
Msg.m_SoundID = Sound;
Server()->SendPackMsg(&Msg, MSGFLAG_VITAL, Target);
if(Target == -2)
Server()->SendPackMsg(&Msg, MSGFLAG_NOSEND, -1);
else
{
int Flag = MSGFLAG_VITAL;
if(Target != -1)
Flag |= MSGFLAG_NORECORD;
Server()->SendPackMsg(&Msg, Flag, Target);
}
}
@ -432,7 +440,23 @@ void CGameContext::SendTuningParams(int ClientID)
Msg.AddInt(pParams[i]);
Server()->SendMsg(&Msg, MSGFLAG_VITAL, ClientID);
}
/*
void CGameContext::SwapTeams()
{
if(!m_pController->IsTeamplay())
return;
SendChat(-1, CGameContext::CHAT_ALL, "Teams were swapped");
for(int i = 0; i < MAX_CLIENTS; ++i)
{
if(m_apPlayers[i] && m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS)
m_apPlayers[i]->SetTeam(m_apPlayers[i]->GetTeam()^1, false);
}
(void)m_pController->CheckTeamBalance();
}
*/
void CGameContext::OnTick()
{
// check tuning
@ -527,7 +551,9 @@ void CGameContext::OnTick()
if(m_VoteEnforce == VOTE_ENFORCE_YES)
{
Server()->SetRconCID(IServer::RCON_CID_VOTE);
Console()->ExecuteLine(m_aVoteCommand);
Server()->SetRconCID(IServer::RCON_CID_SERV);
EndVote();
SendChat(-1, CGameContext::CHAT_ALL, "Vote passed");
@ -960,7 +986,6 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
char aAddrStr[NETADDR_MAXSTRSIZE] = {0};
Server()->GetClientAddr(KickID, aAddrStr, sizeof(aAddrStr));
str_format(aCmd, sizeof(aCmd), "ban %s %d Banned by vote", aAddrStr, g_Config.m_SvVoteKickBantime);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aCmd);
}
m_apPlayers[ClientID]->m_Last_KickVote = time_get();
m_VoteKick = true;
@ -1388,17 +1413,14 @@ void CGameContext::ConSetTeam(IConsole::IResult *pResult, void *pUserData)
CGameContext *pSelf = (CGameContext *)pUserData;
int ClientID = clamp(pResult->GetInteger(0), 0, (int)MAX_CLIENTS-1);
int Team = clamp(pResult->GetInteger(1), -1, 1);
int Delay = 0;
if(pResult->NumArguments() > 2)
Delay = pResult->GetInteger(2);
int Delay = pResult->NumArguments()>2 ? pResult->GetInteger(2) : 0;
if(!pSelf->m_apPlayers[ClientID])
return;
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "moved client %d to team %d", ClientID, Team);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
if(!pSelf->m_apPlayers[ClientID])
return;
pSelf->m_apPlayers[ClientID]->m_TeamChangeTick = pSelf->Server()->Tick()+pSelf->Server()->TickSpeed()*Delay*60;
pSelf->m_apPlayers[ClientID]->SetTeam(Team);
// (void)pSelf->m_pController->CheckTeamBalance();
@ -1410,16 +1432,65 @@ void CGameContext::ConSetTeamAll(IConsole::IResult *pResult, void *pUserData)
int Team = clamp(pResult->GetInteger(0), -1, 1);
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "moved all clients to team %d", Team);
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
str_format(aBuf, sizeof(aBuf), "All players were moved to the %s", pSelf->m_pController->GetTeamName(Team));
pSelf->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
for(int i = 0; i < MAX_CLIENTS; ++i)
if(pSelf->m_apPlayers[i])
pSelf->m_apPlayers[i]->SetTeam(Team);
pSelf->m_apPlayers[i]->SetTeam(Team, false);
// (void)pSelf->m_pController->CheckTeamBalance();
}
/*
void CGameContext::ConSwapTeams(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
pSelf->SwapTeams();
}
void CGameContext::ConShuffleTeams(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
if(!pSelf->m_pController->IsTeamplay())
return;
int CounterRed = 0;
int CounterBlue = 0;
int PlayerTeam = 0;
for(int i = 0; i < MAX_CLIENTS; ++i)
if(pSelf->m_apPlayers[i] && pSelf->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS)
++PlayerTeam;
PlayerTeam = (PlayerTeam+1)/2;
pSelf->SendChat(-1, CGameContext::CHAT_ALL, "Teams were shuffled");
for(int i = 0; i < MAX_CLIENTS; ++i)
{
if(pSelf->m_apPlayers[i] && pSelf->m_apPlayers[i]->GetTeam() != TEAM_SPECTATORS)
{
if(CounterRed == PlayerTeam)
pSelf->m_apPlayers[i]->SetTeam(TEAM_BLUE, false);
else if(CounterBlue == PlayerTeam)
pSelf->m_apPlayers[i]->SetTeam(TEAM_RED, false);
else
{
if(rand() % 2)
{
pSelf->m_apPlayers[i]->SetTeam(TEAM_BLUE, false);
++CounterBlue;
}
else
{
pSelf->m_apPlayers[i]->SetTeam(TEAM_RED, false);
++CounterRed;
}
}
}
}
// (void)pSelf->m_pController->CheckTeamBalance();
}
*/
void CGameContext::ConAddVote(IConsole::IResult *pResult, void *pUserData)
{
CGameContext *pSelf = (CGameContext *)pUserData;
@ -1682,6 +1753,8 @@ void CGameContext::OnConsoleInit()
Console()->Register("say", "r", CFGFLAG_SERVER, ConSay, this, "Say in chat");
Console()->Register("set_team", "ii?i", CFGFLAG_SERVER, ConSetTeam, this, "Set team of player to team");
Console()->Register("set_team_all", "i", CFGFLAG_SERVER, ConSetTeamAll, this, "Set team of all players to team");
//Console()->Register("swap_teams", "", CFGFLAG_SERVER, ConSwapTeams, this, "Swap the current teams");
//Console()->Register("shuffle_teams", "", CFGFLAG_SERVER, ConShuffleTeams, this, "Shuffle the current teams");
Console()->Register("add_vote", "sr", CFGFLAG_SERVER, ConAddVote, this, "Add a voting option");
Console()->Register("remove_vote", "s", CFGFLAG_SERVER, ConRemoveVote, this, "remove a voting option");

View file

@ -55,6 +55,8 @@ class CGameContext : public IGameServer
static void ConSay(IConsole::IResult *pResult, void *pUserData);
static void ConSetTeam(IConsole::IResult *pResult, void *pUserData);
static void ConSetTeamAll(IConsole::IResult *pResult, void *pUserData);
//static void ConSwapTeams(IConsole::IResult *pResult, void *pUserData);
//static void ConShuffleTeams(IConsole::IResult *pResult, void *pUserData);
static void ConAddVote(IConsole::IResult *pResult, void *pUserData);
static void ConRemoveVote(IConsole::IResult *pResult, void *pUserData);
static void ConForceVote(IConsole::IResult *pResult, void *pUserData);
@ -142,6 +144,9 @@ public:
void CheckPureTuning();
void SendTuningParams(int ClientID);
//
//void SwapTeams();
// engine events
virtual void OnInit();
virtual void OnConsoleInit();

View file

@ -439,7 +439,11 @@ void IGameController::ChangeMap(const char *pToMap)
return;
if(m_RoundCount < g_Config.m_SvRoundsPerMap-1)
{
if(g_Config.m_SvRoundSwap)
GameServer()->SwapTeams();
return;
}
// handle maprotation
const char *pMapRotation = g_Config.m_SvMaprotation;

View file

@ -260,6 +260,8 @@ void CGameControllerCTF::Tick()
else
GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_PL, c);
}
// demo record entry
GameServer()->CreateSoundGlobal(SOUND_CTF_GRAB_EN, -2);
break;
}
}

View file

@ -304,7 +304,7 @@ void CPlayer::Respawn()
m_Spawning = true;
}
void CPlayer::SetTeam(int Team)
void CPlayer::SetTeam(int Team, bool DoChatMsg)
{
// clamp the team
Team = GameServer()->m_pController->ClampTeam(Team);
@ -312,8 +312,11 @@ void CPlayer::SetTeam(int Team)
return;
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "'%s' joined the %s", Server()->ClientName(m_ClientID), GameServer()->m_pController->GetTeamName(Team));
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
if(DoChatMsg)
{
str_format(aBuf, sizeof(aBuf), "'%s' joined the %s", Server()->ClientName(m_ClientID), GameServer()->m_pController->GetTeamName(Team));
GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf);
}
KillCharacter();

View file

@ -20,7 +20,7 @@ public:
void TryRespawn();
void Respawn();
void SetTeam(int Team);
void SetTeam(int Team, bool DoChatMsg=true);
int GetTeam() const { return m_Team; };
int GetCID() const { return m_ClientID; };

View file

@ -60,6 +60,7 @@ MACRO_CONFIG_STR(SvMotd, sv_motd, 900, "", CFGFLAG_SERVER, "Message of the day t
MACRO_CONFIG_INT(SvTeamdamage, sv_teamdamage, 0, 0, 1, CFGFLAG_SERVER, "Team damage")
MACRO_CONFIG_STR(SvMaprotation, sv_maprotation, 768, "", CFGFLAG_SERVER, "Maps to rotate between")
MACRO_CONFIG_INT(SvRoundsPerMap, sv_rounds_per_map, 1, 1, 100, CFGFLAG_SERVER, "Number of rounds on each map before rotating")
MACRO_CONFIG_INT(SvRoundSwap, sv_round_swap, 1, 0, 1, CFGFLAG_SERVER, "Swap teams between rounds")
MACRO_CONFIG_INT(SvPowerups, sv_powerups, 1, 0, 1, CFGFLAG_SERVER, "Allow powerups like ninja")
MACRO_CONFIG_INT(SvScorelimit, sv_scorelimit, 20, 0, 1000, CFGFLAG_SERVER, "Score limit (0 disables)")
MACRO_CONFIG_INT(SvTimelimit, sv_timelimit, 0, 0, 1000, CFGFLAG_SERVER, "Time limit in minutes (0 disables)")

View file

@ -1,20 +1,23 @@
/* (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 <base/system.h>
#include <engine/shared/network.h>
#include <engine/shared/config.h>
#include <engine/console.h>
#include <engine/storage.h>
#include <engine/kernel.h>
#include <engine/storage.h>
#include <engine/shared/config.h>
#include <engine/shared/netban.h>
#include <engine/shared/network.h>
#include "mastersrv.h"
enum {
MTU = 1400,
MAX_SERVERS_PER_PACKET=75,
MAX_PACKETS=16,
MAX_SERVERS=MAX_SERVERS_PER_PACKET*MAX_PACKETS,
MAX_BANS=128,
EXPIRE_TIME = 90
};
@ -77,14 +80,7 @@ static CCountPacketData m_CountData;
static CCountPacketData m_CountDataLegacy;
struct CBanEntry
{
NETADDR m_Address;
int64 m_Expire;
};
static CBanEntry m_aBans[MAX_BANS];
static int m_NumBans = 0;
CNetBan m_NetBan;
static CNetClient m_NetChecker; // NAT/FW checker
static CNetClient m_NetOp; // main
@ -217,9 +213,9 @@ void AddCheckserver(NETADDR *pInfo, NETADDR *pAlt, ServerType Type)
}
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr));
net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr), true);
char aAltAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(pAlt, aAltAddrStr, sizeof(aAltAddrStr));
net_addr_str(pAlt, aAltAddrStr, sizeof(aAltAddrStr), true);
dbg_msg("mastersrv", "checking: %s (%s)", aAddrStr, aAltAddrStr);
m_aCheckServers[m_NumCheckServers].m_Address = *pInfo;
m_aCheckServers[m_NumCheckServers].m_AltAddress = *pAlt;
@ -237,7 +233,7 @@ void AddServer(NETADDR *pInfo, ServerType Type)
if(net_addr_comp(&m_aServers[i].m_Address, pInfo) == 0)
{
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr));
net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr), true);
dbg_msg("mastersrv", "updated: %s", aAddrStr);
m_aServers[i].m_Expire = time_get()+time_freq()*EXPIRE_TIME;
return;
@ -252,7 +248,7 @@ void AddServer(NETADDR *pInfo, ServerType Type)
}
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr));
net_addr_str(pInfo, aAddrStr, sizeof(aAddrStr), true);
dbg_msg("mastersrv", "added: %s", aAddrStr);
m_aServers[m_NumServers].m_Address = *pInfo;
m_aServers[m_NumServers].m_Expire = time_get()+time_freq()*EXPIRE_TIME;
@ -271,9 +267,9 @@ void UpdateServers()
if(m_aCheckServers[i].m_TryCount == 10)
{
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&m_aCheckServers[i].m_Address, aAddrStr, sizeof(aAddrStr));
net_addr_str(&m_aCheckServers[i].m_Address, aAddrStr, sizeof(aAddrStr), true);
char aAltAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&m_aCheckServers[i].m_AltAddress, aAltAddrStr, sizeof(aAltAddrStr));
net_addr_str(&m_aCheckServers[i].m_AltAddress, aAltAddrStr, sizeof(aAltAddrStr), true);
dbg_msg("mastersrv", "check failed: %s (%s)", aAddrStr, aAltAddrStr);
// FAIL!!
@ -305,7 +301,7 @@ void PurgeServers()
{
// remove server
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&m_aServers[i].m_Address, aAddrStr, sizeof(aAddrStr));
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--;
@ -315,53 +311,9 @@ void PurgeServers()
}
}
bool CheckBan(NETADDR Addr)
{
for(int i = 0; i < m_NumBans; i++)
{
if(net_addr_comp(&m_aBans[i].m_Address, &Addr) == 0)
{
return true;
}
}
Addr.port = 0;
for(int i = 0; i < m_NumBans; i++)
{
if(net_addr_comp(&m_aBans[i].m_Address, &Addr) == 0)
{
return true;
}
}
return false;
}
void ConAddBan(IConsole::IResult *pResult, void *pUser)
{
if(m_NumBans == MAX_BANS)
{
dbg_msg("mastersrv", "error: banlist is full");
return;
}
if(net_addr_from_str(&m_aBans[m_NumBans].m_Address, pResult->GetString(0)) != 0)
{
dbg_msg("mastersrv", "error: invalid address");
return;
}
if(CheckBan(m_aBans[m_NumBans].m_Address))
{
dbg_msg("mastersrv", "duplicate ban: %s", pResult->GetString(0));
return;
}
dbg_msg("mastersrv", "ban added: %s", pResult->GetString(0));
m_NumBans++;
}
void ReloadBans()
{
m_NumBans = 0;
m_NetBan.UnbanAll();
m_pConsole->ExecuteFile("master.cfg");
}
@ -398,7 +350,7 @@ int main(int argc, const char **argv) // ignore_convention
IStorage *pStorage = CreateStorage("Teeworlds", argc, argv);
m_pConsole = CreateConsole(CFGFLAG_MASTER);
m_pConsole->Register("ban", "s", CFGFLAG_MASTER, ConAddBan, 0, "Ban IP from mastersrv");
m_NetBan.Init(m_pConsole, pStorage);
bool RegisterFail = !pKernel->RegisterInterface(pStorage);
RegisterFail |= !pKernel->RegisterInterface(m_pConsole);
@ -418,7 +370,8 @@ int main(int argc, const char **argv) // ignore_convention
while(m_NetOp.Recv(&Packet))
{
// check if the server is banned
if(CheckBan(Packet.m_Address)) continue;
if(m_NetBan.IsBanned(&Packet.m_Address, 0, 0))
continue;
if(Packet.m_DataSize == sizeof(SERVERBROWSE_HEARTBEAT)+2 &&
mem_comp(Packet.m_pData, SERVERBROWSE_HEARTBEAT, sizeof(SERVERBROWSE_HEARTBEAT)) == 0)
@ -519,7 +472,8 @@ int main(int argc, const char **argv) // ignore_convention
while(m_NetChecker.Recv(&Packet))
{
// check if the server is banned
if(CheckBan(Packet.m_Address)) continue;
if(m_NetBan.IsBanned(&Packet.m_Address, 0, 0))
continue;
if(Packet.m_DataSize == sizeof(SERVERBROWSE_FWRESPONSE) &&
mem_comp(Packet.m_pData, SERVERBROWSE_FWRESPONSE, sizeof(SERVERBROWSE_FWRESPONSE)) == 0)

View file

@ -129,7 +129,7 @@ void Run(int Port, NETADDR Dest)
if(m_ConfigLog)
{
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&From, aAddrStr, sizeof(aAddrStr));
net_addr_str(&From, aAddrStr, sizeof(aAddrStr), true);
dbg_msg("crapnet", "<< %08d %s (%d)", p->m_ID, aAddrStr, p->m_DataSize);
}
}
@ -193,7 +193,7 @@ void Run(int Port, NETADDR Dest)
if(m_ConfigLog)
{
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&p->m_SendTo, aAddrStr, sizeof(aAddrStr));
net_addr_str(&p->m_SendTo, aAddrStr, sizeof(aAddrStr), true);
dbg_msg("crapnet", ">> %08d %s (%d) %s", p->m_ID, aAddrStr, p->m_DataSize, aFlags);
}

View file

@ -113,7 +113,7 @@ static int Run()
int64 NextHeartBeat = 0;
NETADDR BindAddr = {NETTYPE_IPV4, {0},0};
if(!pNet->Open(BindAddr, 0, 0, 0))
if(!pNet->Open(BindAddr, 0, 0, 0, 0))
return 0;
while(1)

View file

@ -0,0 +1,86 @@
/* (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 <base/math.h>
#include <base/system.h>
#include <engine/external/pnglite/pnglite.h>
typedef struct
{
unsigned char r, g, b, a;
} CPixel;
static void TilesetBorderadd(int w, int h, CPixel *pSrc, CPixel *pDest)
{
int TileW = w/16;
int TileH = h/16;
for(int tx = 0; tx < 16; tx++)
{
for(int ty = 0; ty < 16; ty++)
{
for(int x = 0; x < TileW + 4; x++)
{
for(int y = 0; y < TileH + 4; y++)
{
int SourceX = tx * TileW + clamp(x - 2, 0, TileW - 1);
int SourceY = ty * TileH + clamp(y - 2, 0, TileH - 1);
int DestX = tx * (TileW + 4) + x;
int DestY = ty * (TileH + 4) + y;
int SourceI = SourceY * w + SourceX;
int DestI = DestY * (w + 16 * 4) + DestX;
pDest[DestI] = pSrc[SourceI];
}
}
}
}
}
int FixFile(const char *pFileName)
{
png_t Png;
CPixel *pBuffer[2] = {0,0};
png_init(0, 0);
png_open_file(&Png, pFileName);
if(Png.color_type != PNG_TRUECOLOR_ALPHA)
{
dbg_msg("tileset_borderadd", "%s: not an RGBA image", pFileName);
return 1;
}
int w = Png.width;
int h = Png.height;
pBuffer[0] = (CPixel*)mem_alloc(w*h*sizeof(CPixel), 1);
pBuffer[1] = (CPixel*)mem_alloc((w+16*4)*(h+16*4)*sizeof(CPixel), 1);
png_get_data(&Png, (unsigned char *)pBuffer[0]);
png_close_file(&Png);
TilesetBorderadd(w, h, pBuffer[0], pBuffer[1]);
// save here
png_open_file_write(&Png, pFileName);
png_set_data(&Png, w + 16 * 4, h + 16 * 4, 8, PNG_TRUECOLOR_ALPHA, (unsigned char *)pBuffer[1]);
png_close_file(&Png);
return 0;
}
int main(int argc, const char **argv)
{
dbg_logger_stdout();
if(argc == 1)
{
dbg_msg("Usage", "%s FILE1 [ FILE2... ]", argv[0]);
return -1;
}
for(int i = 1; i < argc; i++)
FixFile(argv[i]);
return 0;
}

View file

@ -0,0 +1,86 @@
/* (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 <base/math.h>
#include <base/system.h>
#include <engine/external/pnglite/pnglite.h>
typedef struct
{
unsigned char r, g, b, a;
} CPixel;
static void TilesetBorderrem(int w, int h, CPixel *pSrc, CPixel *pDest)
{
int TileW = w/16;
int TileH = h/16;
for(int tx = 0; tx < 16; tx++)
{
for(int ty = 0; ty < 16; ty++)
{
for(int x = 0; x < TileW - 4; x++)
{
for(int y = 0; y < TileH - 4; y++)
{
int SourceX = tx * TileW + x + 2;
int SourceY = ty * TileH + y + 2;
int DestX = tx * (TileW - 4) + x;
int DestY = ty * (TileH - 4) + y;
int SourceI = SourceY * w + SourceX;
int DestI = DestY * (w - 16 * 4) + DestX;
pDest[DestI] = pSrc[SourceI];
}
}
}
}
}
int FixFile(const char *pFileName)
{
png_t Png;
CPixel *pBuffer[2] = {0,0};
png_init(0, 0);
png_open_file(&Png, pFileName);
if(Png.color_type != PNG_TRUECOLOR_ALPHA)
{
dbg_msg("tileset_borderrem", "%s: not an RGBA image", pFileName);
return 1;
}
int w = Png.width;
int h = Png.height;
pBuffer[0] = (CPixel*)mem_alloc(w*h*sizeof(CPixel), 1);
pBuffer[1] = (CPixel*)mem_alloc((w-16*4)*(h-16*4)*sizeof(CPixel), 1);
png_get_data(&Png, (unsigned char *)pBuffer[0]);
png_close_file(&Png);
TilesetBorderrem(w, h, pBuffer[0], pBuffer[1]);
// save here
png_open_file_write(&Png, pFileName);
png_set_data(&Png, w - 16 * 4, h - 16 * 4, 8, PNG_TRUECOLOR_ALPHA, (unsigned char *)pBuffer[1]);
png_close_file(&Png);
return 0;
}
int main(int argc, const char **argv)
{
dbg_logger_stdout();
if(argc == 1)
{
dbg_msg("Usage", "%s FILE1 [ FILE2... ]", argv[0]);
return -1;
}
for(int i = 1; i < argc; i++)
FixFile(argv[i]);
return 0;
}

View file

@ -0,0 +1,78 @@
/* (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 <base/math.h>
#include <base/system.h>
#include <engine/external/pnglite/pnglite.h>
typedef struct
{
unsigned char r, g, b, a;
} CPixel;
static void TilesetBorderset(int w, int h, CPixel *pSrc, CPixel *pDest)
{
int TileW = w/16;
int TileH = h/16;
for(int tx = 0; tx < 16; tx++)
{
for(int ty = 0; ty < 16; ty++)
{
for(int x = 0; x < TileW; x++)
{
for(int y = 0; y < TileH; y++)
{
#define TILE_INDEX(tx_, ty_, x_, y_) (((ty_) * TileH + (y_)) * w + (tx_) * TileW + (x_))
pDest[TILE_INDEX(tx, ty, x, y)] = pSrc[TILE_INDEX(tx, ty, clamp(x, 2, TileW - 3), clamp(y, 2, TileH - 3))];
}
}
}
}
}
int FixFile(const char *pFileName)
{
png_t Png;
CPixel *pBuffer[2] = {0,0};
png_init(0, 0);
png_open_file(&Png, pFileName);
if(Png.color_type != PNG_TRUECOLOR_ALPHA)
{
dbg_msg("tileset_borderset", "%s: not an RGBA image", pFileName);
return 1;
}
int w = Png.width;
int h = Png.height;
pBuffer[0] = (CPixel*)mem_alloc(w*h*sizeof(CPixel), 1);
pBuffer[1] = (CPixel*)mem_alloc(w*h*sizeof(CPixel), 1);
png_get_data(&Png, (unsigned char *)pBuffer[0]);
png_close_file(&Png);
TilesetBorderset(w, h, pBuffer[0], pBuffer[1]);
// save here
png_open_file_write(&Png, pFileName);
png_set_data(&Png, w, h, 8, PNG_TRUECOLOR_ALPHA, (unsigned char *)pBuffer[1]);
png_close_file(&Png);
return 0;
}
int main(int argc, const char **argv)
{
dbg_logger_stdout();
if(argc == 1)
{
dbg_msg("Usage", "%s FILE1 [ FILE2... ]", argv[0]);
return -1;
}
for(int i = 1; i < argc; i++)
FixFile(argv[i]);
return 0;
}