2011-07-02 06:36:14 +00:00
|
|
|
/* (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 "network.h"
|
|
|
|
|
|
|
|
bool CNetConsole::Open(NETADDR BindAddr, int Flags)
|
|
|
|
{
|
|
|
|
// zero out the whole structure
|
|
|
|
mem_zero(this, sizeof(*this));
|
2011-07-31 00:20:46 +00:00
|
|
|
m_Socket.type = NETTYPE_INVALID;
|
|
|
|
m_Socket.ipv4sock = -1;
|
|
|
|
m_Socket.ipv6sock = -1;
|
2011-07-02 06:36:14 +00:00
|
|
|
|
|
|
|
// open socket
|
2011-07-30 11:40:01 +00:00
|
|
|
m_Socket = net_tcp_create(BindAddr);
|
2011-07-02 06:36:14 +00:00
|
|
|
if(!m_Socket.type)
|
|
|
|
return false;
|
|
|
|
if(net_tcp_listen(m_Socket, NET_MAX_CONSOLE_CLIENTS))
|
|
|
|
return false;
|
2011-07-30 11:40:01 +00:00
|
|
|
net_set_non_blocking(m_Socket);
|
2011-07-02 06:36:14 +00:00
|
|
|
|
2011-07-30 11:40:01 +00:00
|
|
|
for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
|
|
|
|
m_aSlots[i].m_Connection.Reset();
|
2011-07-02 06:36:14 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-07-30 11:40:01 +00:00
|
|
|
void CNetConsole::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser)
|
2011-07-02 06:36:14 +00:00
|
|
|
{
|
|
|
|
m_pfnNewClient = pfnNewClient;
|
|
|
|
m_pfnDelClient = pfnDelClient;
|
|
|
|
m_UserPtr = pUser;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CNetConsole::Close()
|
|
|
|
{
|
2011-07-31 00:20:46 +00:00
|
|
|
for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
|
|
|
|
m_aSlots[i].m_Connection.Disconnect("closing console");
|
|
|
|
|
|
|
|
net_tcp_close(m_Socket);
|
|
|
|
|
2011-07-02 06:36:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CNetConsole::Drop(int ClientID, const char *pReason)
|
|
|
|
{
|
|
|
|
if(m_pfnDelClient)
|
|
|
|
m_pfnDelClient(ClientID, pReason, m_UserPtr);
|
|
|
|
|
|
|
|
m_aSlots[ClientID].m_Connection.Disconnect(pReason);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CNetConsole::AcceptClient(NETSOCKET Socket, const NETADDR *pAddr)
|
|
|
|
{
|
|
|
|
char aError[256] = { 0 };
|
|
|
|
int FreeSlot = -1;
|
|
|
|
|
2011-07-30 11:40:01 +00:00
|
|
|
// look for free slot or multiple client
|
2011-07-02 06:36:14 +00:00
|
|
|
for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if(FreeSlot == -1 && m_aSlots[i].m_Connection.State() == NET_CONNSTATE_OFFLINE)
|
|
|
|
FreeSlot = i;
|
|
|
|
if(m_aSlots[i].m_Connection.State() != NET_CONNSTATE_OFFLINE)
|
|
|
|
{
|
2011-07-30 11:40:01 +00:00
|
|
|
NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();
|
2011-07-02 06:36:14 +00:00
|
|
|
if(net_addr_comp(pAddr, &PeerAddr) == 0)
|
|
|
|
{
|
2011-07-30 11:40:01 +00:00
|
|
|
str_copy(aError, "only one client per IP allowed", sizeof(aError));
|
2011-07-02 06:36:14 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-30 11:40:01 +00:00
|
|
|
// accept client
|
2011-07-02 06:36:14 +00:00
|
|
|
if(!aError[0] && FreeSlot != -1)
|
|
|
|
{
|
|
|
|
m_aSlots[FreeSlot].m_Connection.Init(Socket, pAddr);
|
|
|
|
if(m_pfnNewClient)
|
|
|
|
m_pfnNewClient(FreeSlot, m_UserPtr);
|
2011-07-30 11:40:01 +00:00
|
|
|
return 0;
|
2011-07-02 06:36:14 +00:00
|
|
|
}
|
|
|
|
|
2011-07-30 11:40:01 +00:00
|
|
|
// reject client
|
2011-07-02 06:36:14 +00:00
|
|
|
if(!aError[0])
|
2011-07-30 11:40:01 +00:00
|
|
|
str_copy(aError, "no free slot available", sizeof(aError));
|
2011-07-02 06:36:14 +00:00
|
|
|
|
|
|
|
net_tcp_send(Socket, aError, str_length(aError));
|
|
|
|
net_tcp_close(Socket);
|
|
|
|
|
2011-07-30 11:40:01 +00:00
|
|
|
return -1;
|
2011-07-02 06:36:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int CNetConsole::Update()
|
|
|
|
{
|
|
|
|
NETSOCKET Socket;
|
|
|
|
NETADDR Addr;
|
|
|
|
|
2011-07-31 11:05:12 +00:00
|
|
|
if(net_tcp_accept(m_Socket, &Socket, &Addr) > 0)
|
2011-07-02 06:36:14 +00:00
|
|
|
{
|
2011-07-31 11:05:12 +00:00
|
|
|
int Index = FindBan(Addr);
|
|
|
|
if(Index == -1)
|
|
|
|
AcceptClient(Socket, &Addr);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
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");
|
|
|
|
|
|
|
|
net_tcp_send(Socket, aBuf, str_length(aBuf));
|
|
|
|
net_tcp_close(Socket);
|
|
|
|
}
|
2011-07-02 06:36:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ONLINE)
|
|
|
|
m_aSlots[i].m_Connection.Update();
|
|
|
|
if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ERROR)
|
|
|
|
Drop(i, m_aSlots[i].m_Connection.ErrorString());
|
|
|
|
}
|
|
|
|
|
2011-07-31 11:05:12 +00:00
|
|
|
UpdateBans();
|
|
|
|
|
2011-07-02 06:36:14 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CNetConsole::Recv(char *pLine, int MaxLength, int *pClientID)
|
|
|
|
{
|
|
|
|
for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ONLINE && m_aSlots[i].m_Connection.Recv(pLine, MaxLength))
|
|
|
|
{
|
|
|
|
if(pClientID)
|
|
|
|
*pClientID = i;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CNetConsole::Send(int ClientID, const char *pLine)
|
|
|
|
{
|
2011-07-30 11:40:01 +00:00
|
|
|
if(m_aSlots[ClientID].m_Connection.State() == NET_CONNSTATE_ONLINE)
|
|
|
|
return m_aSlots[ClientID].m_Connection.Send(pLine);
|
|
|
|
else
|
|
|
|
return -1;
|
2011-07-02 06:36:14 +00:00
|
|
|
}
|
2011-07-31 11:05:12 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|