mirror of https://github.com/cppla/ServerStatus
205 lines
5.5 KiB
C++
205 lines
5.5 KiB
C++
#include <system.h>
|
|
#include "netban.h"
|
|
#include "network.h"
|
|
#include "main.h"
|
|
#include "server.h"
|
|
|
|
int CServer::NewClientCallback(int ClientID, void *pUser)
|
|
{
|
|
CServer *pThis = (CServer *)pUser;
|
|
|
|
char aAddrStr[NETADDR_MAXSTRSIZE];
|
|
net_addr_str(pThis->m_Network.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true);
|
|
if(pThis->Main()->Config()->m_Verbose)
|
|
dbg_msg("server", "Connection accepted. ncid=%d addr=%s'", ClientID, aAddrStr);
|
|
|
|
pThis->m_aClients[ClientID].m_State = CClient::STATE_CONNECTED;
|
|
pThis->m_aClients[ClientID].m_TimeConnected = time_get();
|
|
pThis->m_Network.Send(ClientID, "Authentication required:");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser)
|
|
{
|
|
CServer *pThis = (CServer *)pUser;
|
|
|
|
char aAddrStr[NETADDR_MAXSTRSIZE];
|
|
net_addr_str(pThis->m_Network.ClientAddr(ClientID), aAddrStr, sizeof(aAddrStr), true);
|
|
if(pThis->Main()->Config()->m_Verbose)
|
|
dbg_msg("server", "Client dropped. ncid=%d addr=%s reason='%s'", ClientID, aAddrStr, pReason);
|
|
|
|
if(pThis->m_aClients[ClientID].m_State == CClient::STATE_AUTHED)
|
|
pThis->Main()->OnDelClient(ClientID);
|
|
pThis->m_aClients[ClientID].m_State = CClient::STATE_EMPTY;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int CServer::Init(CMain *pMain, const char *Bind, int Port)
|
|
{
|
|
m_pMain = pMain;
|
|
m_NetBan.Init();
|
|
|
|
for(int i = 0; i < NET_MAX_CLIENTS; i++)
|
|
m_aClients[i].m_State = CClient::STATE_EMPTY;
|
|
|
|
m_Ready = false;
|
|
|
|
if(Port == 0)
|
|
{
|
|
dbg_msg("server", "Will not bind to port 0.");
|
|
return 1;
|
|
}
|
|
|
|
NETADDR BindAddr;
|
|
if(Bind[0] && net_host_lookup(Bind, &BindAddr, NETTYPE_ALL) == 0)
|
|
{
|
|
// got bindaddr
|
|
BindAddr.type = NETTYPE_ALL;
|
|
BindAddr.port = Port;
|
|
}
|
|
else
|
|
{
|
|
mem_zero(&BindAddr, sizeof(BindAddr));
|
|
BindAddr.type = NETTYPE_ALL;
|
|
BindAddr.port = Port;
|
|
}
|
|
|
|
if(m_Network.Open(BindAddr, &m_NetBan))
|
|
{
|
|
m_Network.SetCallbacks(NewClientCallback, DelClientCallback, this);
|
|
m_Ready = true;
|
|
dbg_msg("server", "Bound to %s:%d", Bind, Port);
|
|
return 0;
|
|
}
|
|
else
|
|
dbg_msg("server", "Couldn't open socket. Port (%d) might already be in use.", Port);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void CServer::Update()
|
|
{
|
|
if(!m_Ready)
|
|
return;
|
|
|
|
m_NetBan.Update();
|
|
m_Network.Update();
|
|
|
|
char aBuf[NET_MAX_PACKETSIZE];
|
|
int ClientID;
|
|
|
|
while(m_Network.Recv(aBuf, (int)(sizeof(aBuf))-1, &ClientID))
|
|
{
|
|
dbg_assert(m_aClients[ClientID].m_State != CClient::STATE_EMPTY, "Got message from empty slot.");
|
|
if(m_aClients[ClientID].m_State == CClient::STATE_CONNECTED)
|
|
{
|
|
int ID = -1;
|
|
char aUsername[128] = {0};
|
|
char aPassword[128] = {0};
|
|
const char *pTmp;
|
|
|
|
if(!(pTmp = str_find(aBuf, ":"))
|
|
|| (unsigned)(pTmp - aBuf) > sizeof(aUsername) || (unsigned)(str_length(pTmp) - 1) > sizeof(aPassword))
|
|
{
|
|
m_Network.NetBan()->BanAddr(m_Network.ClientAddr(ClientID), 60, "You're an idiot, go away.");
|
|
m_Network.Drop(ClientID, "Fuck off.");
|
|
return;
|
|
}
|
|
|
|
str_copy(aUsername, aBuf, pTmp - aBuf + 1);
|
|
str_copy(aPassword, pTmp + 1, sizeof(aPassword));
|
|
if(!*aUsername || !*aPassword)
|
|
{
|
|
m_Network.NetBan()->BanAddr(m_Network.ClientAddr(ClientID), 60, "You're an idiot, go away.");
|
|
m_Network.Drop(ClientID, "Username and password must not be blank.");
|
|
return;
|
|
}
|
|
|
|
for(int i = 0; i < NET_MAX_CLIENTS; i++)
|
|
{
|
|
if(!Main()->Client(i)->m_Active)
|
|
continue;
|
|
|
|
if(str_comp(Main()->Client(i)->m_aUsername, aUsername) == 0 && str_comp(Main()->Client(i)->m_aPassword, aPassword) == 0)
|
|
ID = i;
|
|
}
|
|
|
|
if(ID == -1)
|
|
{
|
|
m_Network.NetBan()->BanAddr(m_Network.ClientAddr(ClientID), 60, "Wrong username and/or password.");
|
|
m_Network.Drop(ClientID, "Wrong username and/or password.");
|
|
}
|
|
else if(Main()->Client(ID)->m_ClientNetID != -1)
|
|
{
|
|
m_Network.Drop(ClientID, "Only one connection per user allowed.");
|
|
}
|
|
else
|
|
{
|
|
m_aClients[ClientID].m_State = CClient::STATE_AUTHED;
|
|
m_aClients[ClientID].m_LastReceived = time_get();
|
|
m_Network.Send(ClientID, "Authentication successful. Access granted.");
|
|
|
|
if(m_Network.ClientAddr(ClientID)->type == NETTYPE_IPV4)
|
|
m_Network.Send(ClientID, "You are connecting via: IPv4");
|
|
else if(m_Network.ClientAddr(ClientID)->type == NETTYPE_IPV6)
|
|
m_Network.Send(ClientID, "You are connecting via: IPv6");
|
|
|
|
if(Main()->Config()->m_Verbose)
|
|
dbg_msg("server", "ncid=%d authed", ClientID);
|
|
Main()->OnNewClient(ClientID, ID);
|
|
}
|
|
}
|
|
else if(m_aClients[ClientID].m_State == CClient::STATE_AUTHED)
|
|
{
|
|
m_aClients[ClientID].m_LastReceived = time_get();
|
|
if(Main()->Config()->m_Verbose)
|
|
dbg_msg("server", "ncid=%d cmd='%s'", ClientID, aBuf);
|
|
|
|
if(str_comp(aBuf, "logout") == 0)
|
|
m_Network.Drop(ClientID, "Logout. Bye Bye ~");
|
|
else
|
|
Main()->HandleMessage(ClientID, aBuf);
|
|
}
|
|
}
|
|
|
|
for(int i = 0; i < NET_MAX_CLIENTS; ++i)
|
|
{
|
|
if(m_aClients[i].m_State == CClient::STATE_CONNECTED &&
|
|
time_get() > m_aClients[i].m_TimeConnected + 5 * time_freq())
|
|
{
|
|
m_Network.NetBan()->BanAddr(m_Network.ClientAddr(i), 30, "Authentication timeout.");
|
|
m_Network.Drop(i, "Authentication timeout.");
|
|
}
|
|
else if(m_aClients[i].m_State == CClient::STATE_AUTHED &&
|
|
time_get() > m_aClients[i].m_LastReceived + 15 * time_freq())
|
|
m_Network.Drop(i, "Timeout.");
|
|
}
|
|
}
|
|
|
|
void CServer::Send(int ClientID, const char *pLine)
|
|
{
|
|
if(!m_Ready)
|
|
return;
|
|
|
|
if(ClientID == -1)
|
|
{
|
|
for(int i = 0; i < NET_MAX_CLIENTS; i++)
|
|
{
|
|
if(m_aClients[i].m_State == CClient::STATE_AUTHED)
|
|
m_Network.Send(i, pLine);
|
|
}
|
|
}
|
|
else if(ClientID >= 0 && ClientID < NET_MAX_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_AUTHED)
|
|
m_Network.Send(ClientID, pLine);
|
|
}
|
|
|
|
void CServer::Shutdown()
|
|
{
|
|
if(!m_Ready)
|
|
return;
|
|
|
|
m_Network.Close();
|
|
}
|