about summary refs log tree commit diff
path: root/src/engine/shared/econ.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/engine/shared/econ.cpp')
-rw-r--r--src/engine/shared/econ.cpp147
1 files changed, 147 insertions, 0 deletions
diff --git a/src/engine/shared/econ.cpp b/src/engine/shared/econ.cpp
new file mode 100644
index 00000000..ba86e5c0
--- /dev/null
+++ b/src/engine/shared/econ.cpp
@@ -0,0 +1,147 @@
+#include <engine/console.h>
+#include <engine/shared/config.h>
+
+#include "econ.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));
+	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);
+
+	pThis->m_aClients[ClientID].m_State = CClient::STATE_CONNECTED;
+	pThis->m_aClients[ClientID].m_TimeConnected = time_get();
+	return 0;
+}
+
+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));
+	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);
+
+	pThis->m_aClients[ClientID].m_State = CClient::STATE_EMPTY;
+	return 0;
+}
+
+void CEcon::SendLineCB(const char *pLine, void *pUserData)
+{
+	static_cast<CEcon *>(pUserData)->Send(-1, pLine);
+}
+
+void CEcon::ConchainEconOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
+{
+	pfnCallback(pResult, pCallbackUserData);
+	if(pResult->NumArguments() == 1)
+	{
+		CEcon *pThis = static_cast<CEcon *>(pUserData);
+		pThis->Console()->SetPrintOutputLevel(pThis->m_PrintCBIndex, pResult->GetInteger(0));
+	}
+}
+
+void CEcon::Init(IConsole *pConsole)
+{
+	m_pConsole = pConsole;
+
+	for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
+		m_aClients[i].m_State = CClient::STATE_EMPTY;
+
+	m_Ready = false;
+
+	if(g_Config.m_EcPort == 0 || g_Config.m_EcPassword[0] == 0)
+		return;
+
+	NETADDR BindAddr;
+	if(g_Config.m_EcBindaddr[0] && net_host_lookup(g_Config.m_EcBindaddr, &BindAddr, NETTYPE_ALL) == 0)
+		BindAddr.port = g_Config.m_EcPort;
+	else
+	{
+		mem_zero(&BindAddr, sizeof(BindAddr));
+		BindAddr.type = NETTYPE_ALL;
+		BindAddr.port = g_Config.m_EcPort;
+	}
+
+	if(m_NetConsole.Open(BindAddr, 0))
+	{
+		m_NetConsole.SetCallbacks(NewClientCallback, DelClientCallback, this);
+		m_Ready = true;
+		char aBuf[128];
+		str_format(aBuf, sizeof(aBuf), "bound to %s:%d", g_Config.m_EcBindaddr, g_Config.m_EcPort);
+		Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD,"econ", aBuf);
+
+		Console()->Chain("ec_output_level", ConchainEconOutputLevelUpdate, this);
+		m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_EcOutputLevel, SendLineCB, this);
+	}
+	else
+		Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD,"econ", "couldn't open socket. port might already be in use");
+}
+
+void CEcon::Update()
+{
+	if(!m_Ready)
+		return;
+
+	m_NetConsole.Update();
+
+	char aBuf[NET_MAX_PACKETSIZE];
+	int ClientID;
+
+	while(m_NetConsole.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)
+		{
+			if(str_comp(aBuf, g_Config.m_EcPassword) == 0)
+			{
+				m_aClients[ClientID].m_State = CClient::STATE_AUTHED;
+				m_NetConsole.Send(ClientID, "Authentication successful. External console access granted.");
+
+				str_format(aBuf, sizeof(aBuf), "cid=%d authed", ClientID);
+				Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "econ", aBuf);
+			}
+			else
+				m_NetConsole.Send(ClientID, "Wrong password");
+		}
+		else if(m_aClients[ClientID].m_State == CClient::STATE_AUTHED)
+		{
+			char aFormatted[256];
+			str_format(aFormatted, sizeof(aBuf), "cid=%d cmd='%s'", ClientID, aBuf);
+			Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aFormatted);
+			Console()->ExecuteLine(aBuf);
+		}
+	}
+
+	for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; ++i)
+	{
+		if(m_aClients[i].m_State == CClient::STATE_CONNECTED &&
+			time_get() > m_aClients[i].m_TimeConnected + g_Config.m_EcAuthTimeout * time_freq())
+			m_NetConsole.Drop(i, "authentication timeout");
+	}
+}
+
+void CEcon::Send(int ClientID, const char *pLine)
+{
+	if(!m_Ready)
+		return;
+
+	if(ClientID == -1)
+	{
+		for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
+		{
+			if(m_aClients[i].m_State == CClient::STATE_AUTHED)
+				m_NetConsole.Send(i, pLine);
+		}
+	}
+	else if(ClientID >= 0 && ClientID < NET_MAX_CONSOLE_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_AUTHED)
+		m_NetConsole.Send(ClientID, pLine);
+}