clean up econ sockets on shutdown. Closes #804
[twcon.git] / src / engine / shared / econ.cpp
blob0bc3a9889656fca3833dd47bea2cf95cbd27e26d
1 #include <engine/console.h>
2 #include <engine/shared/config.h>
4 #include "econ.h"
6 int CEcon::NewClientCallback(int ClientID, void *pUser)
8 CEcon *pThis = (CEcon *)pUser;
10 NETADDR Addr = pThis->m_NetConsole.ClientAddr(ClientID);
11 char aAddrStr[NETADDR_MAXSTRSIZE];
12 net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
13 char aBuf[128];
14 str_format(aBuf, sizeof(aBuf), "client accepted. cid=%d addr=%s'", ClientID, aAddrStr);
15 pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "econ", aBuf);
17 pThis->m_aClients[ClientID].m_State = CClient::STATE_CONNECTED;
18 pThis->m_aClients[ClientID].m_TimeConnected = time_get();
19 return 0;
22 int CEcon::DelClientCallback(int ClientID, const char *pReason, void *pUser)
24 CEcon *pThis = (CEcon *)pUser;
26 NETADDR Addr = pThis->m_NetConsole.ClientAddr(ClientID);
27 char aAddrStr[NETADDR_MAXSTRSIZE];
28 net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr));
29 char aBuf[256];
30 str_format(aBuf, sizeof(aBuf), "client dropped. cid=%d addr=%s reason='%s'", ClientID, aAddrStr, pReason);
31 pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "econ", aBuf);
33 pThis->m_aClients[ClientID].m_State = CClient::STATE_EMPTY;
34 return 0;
37 void CEcon::SendLineCB(const char *pLine, void *pUserData)
39 static_cast<CEcon *>(pUserData)->Send(-1, pLine);
42 void CEcon::ConchainEconOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
44 pfnCallback(pResult, pCallbackUserData);
45 if(pResult->NumArguments() == 1)
47 CEcon *pThis = static_cast<CEcon *>(pUserData);
48 pThis->Console()->SetPrintOutputLevel(pThis->m_PrintCBIndex, pResult->GetInteger(0));
52 void CEcon::Init(IConsole *pConsole)
54 m_pConsole = pConsole;
56 for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
57 m_aClients[i].m_State = CClient::STATE_EMPTY;
59 m_Ready = false;
61 if(g_Config.m_EcPort == 0 || g_Config.m_EcPassword[0] == 0)
62 return;
64 NETADDR BindAddr;
65 if(g_Config.m_EcBindaddr[0] && net_host_lookup(g_Config.m_EcBindaddr, &BindAddr, NETTYPE_ALL) == 0)
66 BindAddr.port = g_Config.m_EcPort;
67 else
69 mem_zero(&BindAddr, sizeof(BindAddr));
70 BindAddr.type = NETTYPE_ALL;
71 BindAddr.port = g_Config.m_EcPort;
74 if(m_NetConsole.Open(BindAddr, 0))
76 m_NetConsole.SetCallbacks(NewClientCallback, DelClientCallback, this);
77 m_Ready = true;
78 char aBuf[128];
79 str_format(aBuf, sizeof(aBuf), "bound to %s:%d", g_Config.m_EcBindaddr, g_Config.m_EcPort);
80 Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD,"econ", aBuf);
82 Console()->Chain("ec_output_level", ConchainEconOutputLevelUpdate, this);
83 m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_EcOutputLevel, SendLineCB, this);
85 else
86 Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD,"econ", "couldn't open socket. port might already be in use");
89 void CEcon::Update()
91 if(!m_Ready)
92 return;
94 m_NetConsole.Update();
96 char aBuf[NET_MAX_PACKETSIZE];
97 int ClientID;
99 while(m_NetConsole.Recv(aBuf, (int)(sizeof(aBuf))-1, &ClientID))
101 dbg_assert(m_aClients[ClientID].m_State != CClient::STATE_EMPTY, "got message from empty slot");
102 if(m_aClients[ClientID].m_State == CClient::STATE_CONNECTED)
104 if(str_comp(aBuf, g_Config.m_EcPassword) == 0)
106 m_aClients[ClientID].m_State = CClient::STATE_AUTHED;
107 m_NetConsole.Send(ClientID, "Authentication successful. External console access granted.");
109 str_format(aBuf, sizeof(aBuf), "cid=%d authed", ClientID);
110 Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "econ", aBuf);
112 else
113 m_NetConsole.Send(ClientID, "Wrong password");
115 else if(m_aClients[ClientID].m_State == CClient::STATE_AUTHED)
117 char aFormatted[256];
118 str_format(aFormatted, sizeof(aBuf), "cid=%d cmd='%s'", ClientID, aBuf);
119 Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aFormatted);
120 Console()->ExecuteLine(aBuf);
124 for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; ++i)
126 if(m_aClients[i].m_State == CClient::STATE_CONNECTED &&
127 time_get() > m_aClients[i].m_TimeConnected + g_Config.m_EcAuthTimeout * time_freq())
128 m_NetConsole.Drop(i, "authentication timeout");
132 void CEcon::Send(int ClientID, const char *pLine)
134 if(!m_Ready)
135 return;
137 if(ClientID == -1)
139 for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++)
141 if(m_aClients[i].m_State == CClient::STATE_AUTHED)
142 m_NetConsole.Send(i, pLine);
145 else if(ClientID >= 0 && ClientID < NET_MAX_CONSOLE_CLIENTS && m_aClients[ClientID].m_State == CClient::STATE_AUTHED)
146 m_NetConsole.Send(ClientID, pLine);
149 void CEcon::Shutdown()
151 if(!m_Ready)
152 return;
154 m_NetConsole.Close();