From 1ae474689d564e1feba9924842f05e06600d83a1 Mon Sep 17 00:00:00 2001 From: oy Date: Tue, 5 Jul 2011 21:54:10 +0200 Subject: added moderator support for the remote console. #518 --- src/engine/console.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'src/engine/console.h') diff --git a/src/engine/console.h b/src/engine/console.h index f8ec67b0..e650ac47 100644 --- a/src/engine/console.h +++ b/src/engine/console.h @@ -14,7 +14,10 @@ public: { OUTPUT_LEVEL_STANDARD=0, OUTPUT_LEVEL_ADDINFO, - OUTPUT_LEVEL_DEBUG + OUTPUT_LEVEL_DEBUG, + + ACCESS_LEVEL_ADMIN=0, + ACCESS_LEVEL_MOD, }; // TODO: rework this interface to reduce the amount of virtual calls @@ -62,6 +65,8 @@ public: virtual void RegisterPrintCallback(FPrintCallback pfnPrintCallback, void *pUserData) = 0; virtual void Print(int Level, const char *pFrom, const char *pStr) = 0; + + virtual void SetAccessLevel(int AccessLevel) = 0; }; extern IConsole *CreateConsole(int FlagMask); -- cgit 1.4.1 From 571dff6216562387ff020407c147fe8000177c15 Mon Sep 17 00:00:00 2001 From: oy Date: Thu, 14 Jul 2011 22:07:21 +0200 Subject: made rcon auto completion serverside. Closes #97 --- scripts/cmd5.py | 2 +- src/engine/client.h | 1 + src/engine/client/client.cpp | 24 ++++- src/engine/client/client.h | 4 +- src/engine/console.h | 24 ++++- src/engine/server/server.cpp | 95 +++++++++++++++--- src/engine/server/server.h | 9 ++ src/engine/shared/console.cpp | 171 ++++++++++++++++++++++++++++++--- src/engine/shared/console.h | 18 +++- src/engine/shared/protocol.h | 6 +- src/game/client/components/console.cpp | 30 ++++-- src/game/client/components/console.h | 5 +- src/game/server/gamecontext.cpp | 32 +++--- 13 files changed, 356 insertions(+), 65 deletions(-) (limited to 'src/engine/console.h') diff --git a/scripts/cmd5.py b/scripts/cmd5.py index a06d45a7..07e35bb1 100644 --- a/scripts/cmd5.py +++ b/scripts/cmd5.py @@ -30,6 +30,6 @@ for filename in sys.argv[1:]: hash = hashlib.md5(f).hexdigest().lower()[16:] #TODO 0.7: improve nethash creation -if hash == "5c1e637ffddf3a37": +if hash == "71de0f4d82688970": hash = "626fce9a778df4d4" print('#define GAME_NETVERSION_HASH "%s"' % hash) diff --git a/src/engine/client.h b/src/engine/client.h index 65ab761e..966e8f61 100644 --- a/src/engine/client.h +++ b/src/engine/client.h @@ -95,6 +95,7 @@ public: // remote console virtual void RconAuth(const char *pUsername, const char *pPassword) = 0; virtual bool RconAuthed() = 0; + virtual bool UseTempRconCommands() = 0; virtual void Rcon(const char *pLine) = 0; // server info diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 6949c308..90131703 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -536,11 +536,6 @@ void CClient::SendReady() SendMsgEx(&Msg, MSGFLAG_VITAL|MSGFLAG_FLUSH); } -bool CClient::RconAuthed() -{ - return m_RconAuthed; -} - void CClient::RconAuth(const char *pName, const char *pPassword) { if(RconAuthed()) @@ -549,6 +544,7 @@ void CClient::RconAuth(const char *pName, const char *pPassword) CMsgPacker Msg(NETMSG_RCON_AUTH); Msg.AddString(pName, 32); Msg.AddString(pPassword, 32); + Msg.AddInt(1); SendMsgEx(&Msg, MSGFLAG_VITAL); } @@ -726,6 +722,7 @@ void CClient::DisconnectWithReason(const char *pReason) // m_RconAuthed = 0; + m_pConsole->DeregisterTempAll(); m_NetClient.Disconnect(pReason); SetState(IClient::STATE_OFFLINE); m_pMap->Unload(); @@ -1313,11 +1310,28 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket) CMsgPacker Msg(NETMSG_PING_REPLY); SendMsgEx(&Msg, 0); } + else if(Msg == NETMSG_RCON_CMD_ADD) + { + const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC); + const char *pHelp = Unpacker.GetString(CUnpacker::SANITIZE_CC); + const char *pParams = Unpacker.GetString(CUnpacker::SANITIZE_CC); + if(Unpacker.Error() == 0) + m_pConsole->RegisterTemp(pName, pParams, CFGFLAG_SERVER, pHelp); + } + else if(Msg == NETMSG_RCON_CMD_REM) + { + const char *pName = Unpacker.GetString(CUnpacker::SANITIZE_CC); + if(Unpacker.Error() == 0) + m_pConsole->DeregisterTemp(pName); + } else if(Msg == NETMSG_RCON_AUTH_STATUS) { int Result = Unpacker.GetInt(); if(Unpacker.Error() == 0) m_RconAuthed = Result; + m_UseTempRconCommands = Unpacker.GetInt(); + if(Unpacker.Error() != 0) + m_UseTempRconCommands = 0; } else if(Msg == NETMSG_RCON_LINE) { diff --git a/src/engine/client/client.h b/src/engine/client/client.h index fa0ddaf7..3d81f073 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -128,6 +128,7 @@ class CClient : public IClient, public CDemoPlayer::IListner int m_AckGameTick; int m_CurrentRecvTick; int m_RconAuthed; + int m_UseTempRconCommands; // version-checking char m_aVersionStr[10]; @@ -220,7 +221,8 @@ public: void SendEnterGame(); void SendReady(); - virtual bool RconAuthed(); + virtual bool RconAuthed() { return m_RconAuthed != 0; } + virtual bool UseTempRconCommands() { return m_UseTempRconCommands != 0; } void RconAuth(const char *pName, const char *pPassword); virtual void Rcon(const char *pCmd); diff --git a/src/engine/console.h b/src/engine/console.h index e650ac47..7c39cf49 100644 --- a/src/engine/console.h +++ b/src/engine/console.h @@ -10,6 +10,7 @@ class IConsole : public IInterface MACRO_INTERFACE("console", 0) public: + // TODO: rework/cleanup enum { OUTPUT_LEVEL_STANDARD=0, @@ -18,6 +19,10 @@ public: ACCESS_LEVEL_ADMIN=0, ACCESS_LEVEL_MOD, + + TEMPCMD_NAME_LENGTH=32, + TEMPCMD_HELP_LENGTH=64, + TEMPCMD_PARAMS_LENGTH=16, }; // TODO: rework this interface to reduce the amount of virtual calls @@ -38,10 +43,18 @@ public: class CCommandInfo { + protected: + int m_AccessLevel; public: + CCommandInfo() { m_AccessLevel = ACCESS_LEVEL_ADMIN; } + virtual ~CCommandInfo() {} const char *m_pName; const char *m_pHelp; const char *m_pParams; + + virtual const CCommandInfo *NextCommandInfo(int AccessLevel, int FlagMask) const = 0; + + int GetAccessLevel() const { return m_AccessLevel; } }; typedef void (*FPrintCallback)(const char *pStr, void *pUser); @@ -49,12 +62,15 @@ public: typedef void (*FCommandCallback)(IResult *pResult, void *pUserData); typedef void (*FChainCommandCallback)(IResult *pResult, void *pUserData, FCommandCallback pfnCallback, void *pCallbackUserData); - virtual CCommandInfo *GetCommandInfo(const char *pName, int FlagMask) = 0; - virtual void PossibleCommands(const char *pStr, int FlagMask, FPossibleCallback pfnCallback, void *pUser) = 0; + virtual const CCommandInfo *FirstCommandInfo(int AccessLevel, int Flagmask) const = 0; + virtual const CCommandInfo *GetCommandInfo(const char *pName, int FlagMask, bool Temp) = 0; + virtual void PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser) = 0; virtual void ParseArguments(int NumArgs, const char **ppArguments) = 0; - virtual void Register(const char *pName, const char *pParams, - int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) = 0; + virtual void Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp) = 0; + virtual void RegisterTemp(const char *pName, const char *pParams, int Flags, const char *pHelp) = 0; + virtual void DeregisterTemp(const char *pName) = 0; + virtual void DeregisterTempAll() = 0; virtual void Chain(const char *pName, FChainCommandCallback pfnChainFunc, void *pUser) = 0; virtual void StoreCommands(bool Store) = 0; diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 24d3b317..17df19ed 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -580,6 +580,7 @@ int CServer::NewClientCallback(int ClientID, void *pUser) pThis->m_aClients[ClientID].m_Country = -1; pThis->m_aClients[ClientID].m_Authed = AUTHED_NO; pThis->m_aClients[ClientID].m_AuthTries = 0; + pThis->m_aClients[ClientID].m_pRconCmdToSend = 0; pThis->m_aClients[ClientID].Reset(); return 0; } @@ -605,6 +606,7 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser) pThis->m_aClients[ClientID].m_Country = -1; pThis->m_aClients[ClientID].m_Authed = AUTHED_NO; pThis->m_aClients[ClientID].m_AuthTries = 0; + pThis->m_aClients[ClientID].m_pRconCmdToSend = 0; pThis->m_aClients[ClientID].m_Snapshots.PurgeAll(); return 0; } @@ -649,6 +651,37 @@ void CServer::SendRconLineAuthed(const char *pLine, void *pUser) ReentryGuard--; } +void CServer::SendRconCmdAdd(const IConsole::CCommandInfo *pCommandInfo, int ClientID) +{ + CMsgPacker Msg(NETMSG_RCON_CMD_ADD); + Msg.AddString(pCommandInfo->m_pName, 32); + Msg.AddString(pCommandInfo->m_pHelp, 64); + Msg.AddString(pCommandInfo->m_pParams, 16); + SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); +} + +void CServer::SendRconCmdRem(const IConsole::CCommandInfo *pCommandInfo, int ClientID) +{ + CMsgPacker Msg(NETMSG_RCON_CMD_REM); + Msg.AddString(pCommandInfo->m_pName, 256); + SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); +} + +void CServer::UpdateClientRconCommands() +{ + int ClientID = Tick() % MAX_CLIENTS; + + if(m_aClients[ClientID].m_State != CClient::STATE_EMPTY && m_aClients[ClientID].m_Authed) + { + int ConsoleAccessLevel = m_aClients[ClientID].m_Authed == AUTHED_ADMIN ? IConsole::ACCESS_LEVEL_ADMIN : IConsole::ACCESS_LEVEL_MOD; + for(int i = 0; i < MAX_RCONCMD_SEND && m_aClients[ClientID].m_pRconCmdToSend; ++i) + { + SendRconCmdAdd(m_aClients[ClientID].m_pRconCmdToSend, ClientID); + m_aClients[ClientID].m_pRconCmdToSend = m_aClients[ClientID].m_pRconCmdToSend->NextCommandInfo(ConsoleAccessLevel, CFGFLAG_SERVER); + } + } +} + void CServer::ProcessClientPacket(CNetChunk *pPacket) { int ClientID = pPacket->m_ClientID; @@ -843,10 +876,14 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) else if(g_Config.m_SvRconPassword[0] && str_comp(pPw, g_Config.m_SvRconPassword) == 0) { CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS); - Msg.AddInt(1); + Msg.AddInt(1); //authed + Msg.AddInt(1); //cmdlist SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); m_aClients[ClientID].m_Authed = AUTHED_ADMIN; + int SendRconCmds = Unpacker.GetInt(); + if(Unpacker.Error() == 0 && SendRconCmds) + m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_ADMIN, CFGFLAG_SERVER); SendRconLine(ClientID, "Admin authentication successful. Full remote console access granted."); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (admin)", ClientID); @@ -855,10 +892,14 @@ void CServer::ProcessClientPacket(CNetChunk *pPacket) else if(g_Config.m_SvRconModPassword[0] && str_comp(pPw, g_Config.m_SvRconModPassword) == 0) { CMsgPacker Msg(NETMSG_RCON_AUTH_STATUS); - Msg.AddInt(1); + Msg.AddInt(1); //authed + Msg.AddInt(1); //cmdlist SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); m_aClients[ClientID].m_Authed = AUTHED_MOD; + int SendRconCmds = Unpacker.GetInt(); + if(Unpacker.Error() == 0 && SendRconCmds) + m_aClients[ClientID].m_pRconCmdToSend = Console()->FirstCommandInfo(IConsole::ACCESS_LEVEL_MOD, CFGFLAG_SERVER); SendRconLine(ClientID, "Moderator authentication successful. Limited remote console access granted."); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "ClientID=%d authed (moderator)", ClientID); @@ -1243,6 +1284,8 @@ int CServer::Run() { if(g_Config.m_SvHighBandwidth || (m_CurrentGameTick%2) == 0) DoSnapshot(); + + UpdateClientRconCommands(); } // master server stuff @@ -1512,26 +1555,56 @@ void CServer::ConchainMaxclientsperipUpdate(IConsole::IResult *pResult, void *pU ((CServer *)pUserData)->m_NetServer.SetMaxClientsPerIP(pResult->GetInteger(0)); } +void CServer::ConchainModCommandUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) +{ + if(pResult->NumArguments() == 2) + { + CServer *pThis = static_cast(pUserData); + const IConsole::CCommandInfo *pInfo = pThis->Console()->GetCommandInfo(pResult->GetString(0), CFGFLAG_SERVER, false); + int OldAccessLevel; + if(pInfo) + OldAccessLevel = pInfo->GetAccessLevel(); + pfnCallback(pResult, pCallbackUserData); + if(pInfo && OldAccessLevel != pInfo->GetAccessLevel()) + { + for(int i = 0; i < MAX_CLIENTS; ++i) + { + if(pThis->m_aClients[i].m_State == CServer::CClient::STATE_EMPTY || pThis->m_aClients[i].m_Authed != CServer::AUTHED_MOD || + (pThis->m_aClients[i].m_pRconCmdToSend && str_comp(pResult->GetString(0), pThis->m_aClients[i].m_pRconCmdToSend->m_pName) >= 0)) + continue; + + if(OldAccessLevel == IConsole::ACCESS_LEVEL_ADMIN) + pThis->SendRconCmdAdd(pInfo, i); + else + pThis->SendRconCmdRem(pInfo, i); + } + } + } + else + pfnCallback(pResult, pCallbackUserData); +} + void CServer::RegisterCommands() { m_pConsole = Kernel()->RequestInterface(); - Console()->Register("kick", "i?r", CFGFLAG_SERVER, ConKick, this, ""); - Console()->Register("ban", "s?ir", CFGFLAG_SERVER|CFGFLAG_STORE, ConBan, this, ""); - Console()->Register("unban", "s", CFGFLAG_SERVER|CFGFLAG_STORE, ConUnban, this, ""); - Console()->Register("bans", "", CFGFLAG_SERVER|CFGFLAG_STORE, ConBans, this, ""); - Console()->Register("status", "", CFGFLAG_SERVER, ConStatus, this, ""); - Console()->Register("shutdown", "", CFGFLAG_SERVER, ConShutdown, this, ""); + 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("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("record", "?s", CFGFLAG_SERVER|CFGFLAG_STORE, ConRecord, this, ""); - Console()->Register("stoprecord", "", CFGFLAG_SERVER, ConStopRecord, this, ""); + Console()->Register("record", "?s", CFGFLAG_SERVER|CFGFLAG_STORE, ConRecord, this, "Record to a file"); + Console()->Register("stoprecord", "", CFGFLAG_SERVER, ConStopRecord, this, "Stop recording"); - Console()->Register("reload", "", CFGFLAG_SERVER, ConMapReload, this, ""); + Console()->Register("reload", "", CFGFLAG_SERVER, ConMapReload, this, "Reload the map"); Console()->Chain("sv_name", ConchainSpecialInfoupdate, this); Console()->Chain("password", ConchainSpecialInfoupdate, this); Console()->Chain("sv_max_clients_per_ip", ConchainMaxclientsperipUpdate, this); + Console()->Chain("mod_command", ConchainModCommandUpdate, this); } diff --git a/src/engine/server/server.h b/src/engine/server/server.h index 72c82d4d..5b6e038d 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -54,6 +54,8 @@ public: AUTHED_NO=0, AUTHED_MOD, AUTHED_ADMIN, + + MAX_RCONCMD_SEND=16, }; class CClient @@ -100,6 +102,8 @@ public: int m_Authed; int m_AuthTries; + const IConsole::CCommandInfo *m_pRconCmdToSend; + void Reset(); }; @@ -169,6 +173,10 @@ public: void SendRconLine(int ClientID, const char *pLine); static void SendRconLineAuthed(const char *pLine, void *pUser); + void SendRconCmdAdd(const IConsole::CCommandInfo *pCommandInfo, int ClientID); + void SendRconCmdRem(const IConsole::CCommandInfo *pCommandInfo, int ClientID); + void UpdateClientRconCommands(); + void ProcessClientPacket(CNetChunk *pPacket); void SendServerInfo(NETADDR *pAddr, int Token); @@ -197,6 +205,7 @@ public: static void ConMapReload(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); void RegisterCommands(); diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index 588abd61..847fb140 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -33,6 +33,29 @@ float CConsole::CResult::GetFloat(unsigned Index) return str_tofloat(m_apArgs[Index]); } +const IConsole::CCommandInfo *CConsole::CCommand::NextCommandInfo(int AccessLevel, int FlagMask) const +{ + const CCommand *pInfo = m_pNext; + while(pInfo) + { + if(pInfo->m_Flags&FlagMask && pInfo->m_AccessLevel >= AccessLevel) + break; + pInfo = pInfo->m_pNext; + } + return pInfo; +} + +const IConsole::CCommandInfo *CConsole::FirstCommandInfo(int AccessLevel, int FlagMask) const +{ + for(const CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) + { + if(pCommand->m_Flags&FlagMask && pCommand->GetAccessLevel() >= AccessLevel) + return pCommand; + } + + return 0; +} + // the maximum number of tokens occurs in a string of length CONSOLE_MAX_STR_LENGTH with tokens size 1 separated by single spaces @@ -258,7 +281,7 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr) if(pCommand) { - if(pCommand->m_AccessLevel >= m_AccessLevel) + if(pCommand->GetAccessLevel() >= m_AccessLevel) { int IsStrokeCommand = 0; if(Result.m_pCommand[0] == '+') @@ -305,11 +328,11 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr) } } -void CConsole::PossibleCommands(const char *pStr, int FlagMask, FPossibleCallback pfnCallback, void *pUser) +void CConsole::PossibleCommands(const char *pStr, int FlagMask, bool Temp, FPossibleCallback pfnCallback, void *pUser) { for(CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) { - if(pCommand->m_Flags&FlagMask) + if(pCommand->m_Flags&FlagMask && pCommand->m_Temp == Temp) { if(str_find_nocase(pCommand->m_pName, pStr)) pfnCallback(pCommand->m_pName, pUser); @@ -403,11 +426,11 @@ void CConsole::ConModCommandAccess(IResult *pResult, void *pUser) { if(pResult->NumArguments() == 2) { - pCommand->m_AccessLevel = clamp(pResult->GetInteger(1), (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_MOD)); - str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is now %s", pResult->GetString(0), pCommand->m_AccessLevel ? "enabled" : "disabled"); + pCommand->SetAccessLevel(pResult->GetInteger(1)); + str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is now %s", pResult->GetString(0), pCommand->GetAccessLevel() ? "enabled" : "disabled"); } else - str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is %s", pResult->GetString(0), pCommand->m_AccessLevel ? "enabled" : "disabled"); + str_format(aBuf, sizeof(aBuf), "moderator access for '%s' is %s", pResult->GetString(0), pCommand->GetAccessLevel() ? "enabled" : "disabled"); } else str_format(aBuf, sizeof(aBuf), "No such command: '%s'.", pResult->GetString(0)); @@ -424,7 +447,7 @@ void CConsole::ConModCommandStatus(IResult *pResult, void *pUser) for(CCommand *pCommand = pConsole->m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) { - if(pCommand->m_Flags&pConsole->m_FlagMask && pCommand->m_AccessLevel == ACCESS_LEVEL_MOD) + if(pCommand->m_Flags&pConsole->m_FlagMask && pCommand->GetAccessLevel() == ACCESS_LEVEL_MOD) { int Length = str_length(pCommand->m_pName); if(Used + Length + 2 < (int)(sizeof(aBuf))) @@ -531,6 +554,8 @@ CConsole::CConsole(int FlagMask) { m_FlagMask = FlagMask; m_AccessLevel = ACCESS_LEVEL_ADMIN; + m_pRecycleList = 0; + m_TempCommands.Reset(); m_StoreCommands = true; m_paStrokeStr[0] = "0"; m_paStrokeStr[1] = "1"; @@ -592,20 +617,131 @@ 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 && m_pFirstCommand->m_pNext) + pCommand->m_pNext = m_pFirstCommand; + else + pCommand->m_pNext = 0; + m_pFirstCommand = pCommand; + } + else + { + 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) + { + pCommand->m_pNext = p->m_pNext; + p->m_pNext = pCommand; + break; + } + } + } +} + 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; pCommand->m_pfnCallback = pfnFunc; pCommand->m_pUserData = pUser; - pCommand->m_pHelp = pHelp; + pCommand->m_pName = pName; + pCommand->m_pHelp = pHelp; pCommand->m_pParams = pParams; + + pCommand->m_Flags = Flags; + pCommand->m_Temp = false; + + AddCommandSorted(pCommand); +} + +void CConsole::RegisterTemp(const char *pName, const char *pParams, int Flags, const char *pHelp) +{ + CCommand *pCommand; + if(m_pRecycleList) + { + pCommand = m_pRecycleList; + str_copy(const_cast(pCommand->m_pName), pName, TEMPCMD_NAME_LENGTH); + str_copy(const_cast(pCommand->m_pHelp), pHelp, TEMPCMD_HELP_LENGTH); + str_copy(const_cast(pCommand->m_pParams), pParams, TEMPCMD_PARAMS_LENGTH); + + m_pRecycleList = m_pRecycleList->m_pNext; + } + else + { + pCommand = new(m_TempCommands.Allocate(sizeof(CCommand))) CCommand; + char *pMem = static_cast(m_TempCommands.Allocate(TEMPCMD_NAME_LENGTH)); + str_copy(pMem, pName, TEMPCMD_NAME_LENGTH); + pCommand->m_pName = pMem; + pMem = static_cast(m_TempCommands.Allocate(TEMPCMD_HELP_LENGTH)); + str_copy(pMem, pHelp, TEMPCMD_HELP_LENGTH); + pCommand->m_pHelp = pMem; + pMem = static_cast(m_TempCommands.Allocate(TEMPCMD_PARAMS_LENGTH)); + str_copy(pMem, pParams, TEMPCMD_PARAMS_LENGTH); + pCommand->m_pParams = pMem; + } + + pCommand->m_pfnCallback = 0; + pCommand->m_pUserData = 0; pCommand->m_Flags = Flags; - pCommand->m_AccessLevel = ACCESS_LEVEL_ADMIN; + pCommand->m_Temp = true; + + AddCommandSorted(pCommand); +} + +void CConsole::DeregisterTemp(const char *pName) +{ + if(!m_pFirstCommand) + return; + + CCommand *pRemoved = 0; + + // remove temp entry from command list + if(m_pFirstCommand->m_Temp && str_comp(m_pFirstCommand->m_pName, pName) == 0) + { + pRemoved = m_pFirstCommand; + m_pFirstCommand = m_pFirstCommand->m_pNext; + } + else + { + for(CCommand *pCommand = m_pFirstCommand; pCommand->m_pNext; pCommand = pCommand->m_pNext) + if(pCommand->m_pNext->m_Temp && str_comp(pCommand->m_pNext->m_pName, pName) == 0) + { + pRemoved = pCommand->m_pNext; + pCommand->m_pNext = pCommand->m_pNext->m_pNext; + break; + } + } + + // add to recycle list + if(pRemoved) + { + pRemoved->m_pNext = m_pRecycleList; + m_pRecycleList = pRemoved; + } +} + +void CConsole::DeregisterTempAll() +{ + // set non temp as first one + for(; m_pFirstCommand && m_pFirstCommand->m_Temp; m_pFirstCommand = m_pFirstCommand->m_pNext); + + // remove temp entries from command list + for(CCommand *pCommand = m_pFirstCommand; pCommand && pCommand->m_pNext; pCommand = pCommand->m_pNext) + { + CCommand *pNext = pCommand->m_pNext; + if(pNext->m_Temp) + { + for(; pNext && pNext->m_Temp; pNext = pNext->m_pNext); + pCommand->m_pNext = pNext; + } + } - pCommand->m_pNext = m_pFirstCommand; - m_pFirstCommand = pCommand; + m_TempCommands.Reset(); + m_pRecycleList = 0; } void CConsole::Con_Chain(IResult *pResult, void *pUserData) @@ -651,9 +787,18 @@ void CConsole::StoreCommands(bool Store) } -IConsole::CCommandInfo *CConsole::GetCommandInfo(const char *pName, int FlagMask) +const IConsole::CCommandInfo *CConsole::GetCommandInfo(const char *pName, int FlagMask, bool Temp) { - return FindCommand(pName, FlagMask); + for(CCommand *pCommand = m_pFirstCommand; pCommand; pCommand = pCommand->m_pNext) + { + if(pCommand->m_Flags&FlagMask && pCommand->m_Temp == Temp) + { + if(str_comp_nocase(pCommand->m_pName, pName) == 0) + return pCommand; + } + } + + return 0; } diff --git a/src/engine/shared/console.h b/src/engine/shared/console.h index 14c48581..b29f3202 100644 --- a/src/engine/shared/console.h +++ b/src/engine/shared/console.h @@ -13,9 +13,13 @@ class CConsole : public IConsole public: CCommand *m_pNext; int m_Flags; - int m_AccessLevel; + bool m_Temp; FCommandCallback m_pfnCallback; void *m_pUserData; + + virtual const CCommandInfo *NextCommandInfo(int AccessLevel, int FlagMask) const; + + void SetAccessLevel(int AccessLevel) { m_AccessLevel = clamp(AccessLevel, (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_MOD)); } }; @@ -44,6 +48,9 @@ class CConsole : public IConsole class IStorage *m_pStorage; int m_AccessLevel; + CCommand *m_pRecycleList; + CHeap m_TempCommands; + static void Con_Chain(IResult *pResult, void *pUserData); static void Con_Echo(IResult *pResult, void *pUserData); static void Con_Exec(IResult *pResult, void *pUserData); @@ -138,16 +145,21 @@ class CConsole : public IConsole } } m_ExecutionQueue; + void AddCommandSorted(CCommand *pCommand); CCommand *FindCommand(const char *pName, int FlagMask); public: CConsole(int FlagMask); - virtual CCommandInfo *GetCommandInfo(const char *pName, int FlagMask); - virtual void PossibleCommands(const char *pStr, int FlagMask, FPossibleCallback pfnCallback, void *pUser) ; + 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); virtual void ParseArguments(int NumArgs, const char **ppArguments); virtual void Register(const char *pName, const char *pParams, int Flags, FCommandCallback pfnFunc, void *pUser, const char *pHelp); + virtual void RegisterTemp(const char *pName, const char *pParams, int Flags, const char *pHelp); + virtual void DeregisterTemp(const char *pName); + virtual void DeregisterTempAll(); virtual void Chain(const char *pName, FChainCommandCallback pfnChainFunc, void *pUser); virtual void StoreCommands(bool Store); diff --git a/src/engine/shared/protocol.h b/src/engine/shared/protocol.h index 4a4895ad..ba04da8a 100644 --- a/src/engine/shared/protocol.h +++ b/src/engine/shared/protocol.h @@ -65,7 +65,11 @@ enum // sent by both NETMSG_PING, NETMSG_PING_REPLY, - NETMSG_ERROR + NETMSG_ERROR, + + // sent by server (todo: move it up) + NETMSG_RCON_CMD_ADD, + NETMSG_RCON_CMD_REM, }; // this should be revised diff --git a/src/game/client/components/console.cpp b/src/game/client/components/console.cpp index 2f5c49ad..9b16ce0d 100644 --- a/src/game/client/components/console.cpp +++ b/src/game/client/components/console.cpp @@ -51,7 +51,7 @@ CGameConsole::CInstance::CInstance(int Type) m_CompletionChosen = -1; m_CompletionRenderOffset = 0.0f; - m_pCommand = 0x0; + m_IsCommand = false; } void CGameConsole::CInstance::Init(CGameConsole *pGameConsole) @@ -147,14 +147,16 @@ void CGameConsole::CInstance::OnInput(IInput::CEvent Event) { m_CompletionChosen++; m_CompletionEnumerationCount = 0; - m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, PossibleCommandsCompleteCallback, this); + m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, m_Type != CGameConsole::CONSOLETYPE_LOCAL && + m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands(), PossibleCommandsCompleteCallback, this); // handle wrapping if(m_CompletionEnumerationCount && m_CompletionChosen >= m_CompletionEnumerationCount) { m_CompletionChosen %= m_CompletionEnumerationCount; m_CompletionEnumerationCount = 0; - m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, PossibleCommandsCompleteCallback, this); + m_pGameConsole->m_pConsole->PossibleCommands(m_aCompletionBuffer, m_CompletionFlagmask, m_Type != CGameConsole::CONSOLETYPE_LOCAL && + m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands(), PossibleCommandsCompleteCallback, this); } } } @@ -190,7 +192,17 @@ void CGameConsole::CInstance::OnInput(IInput::CEvent Event) aBuf[i] = *pSrc; aBuf[i] = 0; - m_pCommand = m_pGameConsole->m_pConsole->GetCommandInfo(aBuf, m_CompletionFlagmask); + const IConsole::CCommandInfo *pCommand = m_pGameConsole->m_pConsole->GetCommandInfo(aBuf, m_CompletionFlagmask, + m_Type != CGameConsole::CONSOLETYPE_LOCAL && m_pGameConsole->Client()->RconAuthed() && m_pGameConsole->Client()->UseTempRconCommands()); + if(pCommand) + { + m_IsCommand = true; + str_copy(m_aCommandName, pCommand->m_pName, IConsole::TEMPCMD_NAME_LENGTH); + str_copy(m_aCommandHelp, pCommand->m_pHelp, IConsole::TEMPCMD_HELP_LENGTH); + str_copy(m_aCommandParams, pCommand->m_pParams, IConsole::TEMPCMD_PARAMS_LENGTH); + } + else + m_IsCommand = false; } } } @@ -449,19 +461,19 @@ void CGameConsole::OnRender() { if(pConsole->m_Input.GetString()[0] != 0) { - m_pConsole->PossibleCommands(pConsole->m_aCompletionBuffer, pConsole->m_CompletionFlagmask, PossibleCommandsRenderCallback, &Info); + m_pConsole->PossibleCommands(pConsole->m_aCompletionBuffer, pConsole->m_CompletionFlagmask, m_ConsoleType != CGameConsole::CONSOLETYPE_LOCAL && + Client()->RconAuthed() && Client()->UseTempRconCommands(), PossibleCommandsRenderCallback, &Info); pConsole->m_CompletionRenderOffset = Info.m_Offset; if(Info.m_EnumCount <= 0) { - if(pConsole->m_pCommand) + if(pConsole->m_IsCommand) { - char aBuf[512]; - str_format(aBuf, sizeof(aBuf), "Help: %s ", pConsole->m_pCommand->m_pHelp); + str_format(aBuf, sizeof(aBuf), "Help: %s ", pConsole->m_aCommandHelp); TextRender()->TextEx(&Info.m_Cursor, aBuf, -1); TextRender()->TextColor(0.75f, 0.75f, 0.75f, 1); - str_format(aBuf, sizeof(aBuf), "Syntax: %s %s", pConsole->m_pCommand->m_pName, pConsole->m_pCommand->m_pParams); + str_format(aBuf, sizeof(aBuf), "Syntax: %s %s", pConsole->m_aCommandName, pConsole->m_aCommandParams); TextRender()->TextEx(&Info.m_Cursor, aBuf, -1); } } diff --git a/src/game/client/components/console.h b/src/game/client/components/console.h index 003a9423..326fb076 100644 --- a/src/game/client/components/console.h +++ b/src/game/client/components/console.h @@ -33,7 +33,10 @@ class CGameConsole : public CComponent int m_CompletionFlagmask; float m_CompletionRenderOffset; - IConsole::CCommandInfo *m_pCommand; + bool m_IsCommand; + char m_aCommandName[IConsole::TEMPCMD_NAME_LENGTH]; + char m_aCommandHelp[IConsole::TEMPCMD_HELP_LENGTH]; + char m_aCommandParams[IConsole::TEMPCMD_PARAMS_LENGTH]; CInstance(int t); void Init(CGameConsole *pGameConsole); diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 52eaca89..6b029bbd 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -1317,22 +1317,22 @@ void CGameContext::OnConsoleInit() m_pServer = Kernel()->RequestInterface(); m_pConsole = Kernel()->RequestInterface(); - Console()->Register("tune", "si", CFGFLAG_SERVER, ConTuneParam, this, ""); - Console()->Register("tune_reset", "", CFGFLAG_SERVER, ConTuneReset, this, ""); - Console()->Register("tune_dump", "", CFGFLAG_SERVER, ConTuneDump, this, ""); - - Console()->Register("change_map", "?r", CFGFLAG_SERVER|CFGFLAG_STORE, ConChangeMap, this, ""); - Console()->Register("restart", "?i", CFGFLAG_SERVER|CFGFLAG_STORE, ConRestart, this, ""); - Console()->Register("broadcast", "r", CFGFLAG_SERVER, ConBroadcast, this, ""); - Console()->Register("say", "r", CFGFLAG_SERVER, ConSay, this, ""); - Console()->Register("set_team", "ii?i", CFGFLAG_SERVER, ConSetTeam, this, ""); - Console()->Register("set_team_all", "i", CFGFLAG_SERVER, ConSetTeamAll, this, ""); - - Console()->Register("add_vote", "sr", CFGFLAG_SERVER, ConAddVote, this, ""); - Console()->Register("remove_vote", "s", CFGFLAG_SERVER, ConRemoveVote, this, ""); - Console()->Register("force_vote", "ss?r", CFGFLAG_SERVER, ConForceVote, this, ""); - Console()->Register("clear_votes", "", CFGFLAG_SERVER, ConClearVotes, this, ""); - Console()->Register("vote", "r", CFGFLAG_SERVER, ConVote, this, ""); + Console()->Register("tune", "si", CFGFLAG_SERVER, ConTuneParam, this, "Tune variable to value"); + Console()->Register("tune_reset", "", CFGFLAG_SERVER, ConTuneReset, this, "Reset tuning"); + Console()->Register("tune_dump", "", CFGFLAG_SERVER, ConTuneDump, this, "Dump tuning"); + + Console()->Register("change_map", "?r", CFGFLAG_SERVER|CFGFLAG_STORE, ConChangeMap, this, "Change map"); + Console()->Register("restart", "?i", CFGFLAG_SERVER|CFGFLAG_STORE, ConRestart, this, "Restart in x seconds"); + Console()->Register("broadcast", "r", CFGFLAG_SERVER, ConBroadcast, this, "Broadcast message"); + 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("add_vote", "sr", CFGFLAG_SERVER, ConAddVote, this, "Add a voting option"); + Console()->Register("remove_vote", "s", CFGFLAG_SERVER, ConRemoveVote, this, "remove a voting option"); + Console()->Register("force_vote", "ss?r", CFGFLAG_SERVER, ConForceVote, this, "Force a voting option"); + Console()->Register("clear_votes", "", CFGFLAG_SERVER, ConClearVotes, this, "Clears the voting options"); + Console()->Register("vote", "r", CFGFLAG_SERVER, ConVote, this, "Force a vote to yes/no"); Console()->Chain("sv_motd", ConchainSpecialMotdupdate, this); } -- cgit 1.4.1 From a0a62bcd70d1d8c0874d5ff52e443b5fb417854c Mon Sep 17 00:00:00 2001 From: oy Date: Sat, 30 Jul 2011 13:40:01 +0200 Subject: fixed econ feature and tcp --- src/base/system.c | 44 +++++--- src/engine/console.h | 5 +- src/engine/server/server.cpp | 127 +++------------------ src/engine/server/server.h | 29 +---- src/engine/shared/config_variables.h | 10 +- src/engine/shared/console.cpp | 32 ++++-- src/engine/shared/console.h | 12 +- src/engine/shared/econ.cpp | 147 ++++++++++++++++++++++++ src/engine/shared/econ.h | 43 ++++++++ src/engine/shared/network.h | 24 ++-- src/engine/shared/network_console.cpp | 49 +++----- src/engine/shared/network_console_conn.cpp | 172 +++++++++++++++-------------- src/game/client/components/console.cpp | 14 ++- src/game/client/components/console.h | 2 + 14 files changed, 408 insertions(+), 302 deletions(-) create mode 100644 src/engine/shared/econ.cpp create mode 100644 src/engine/shared/econ.h (limited to 'src/engine/console.h') diff --git a/src/base/system.c b/src/base/system.c index 551b3f1b..466e3ca6 100644 --- a/src/base/system.c +++ b/src/base/system.c @@ -42,10 +42,6 @@ #include #include #include - - #ifndef EWOULDBLOCK - #define EWOULDBLOCK WSAEWOULDBLOCK - #endif #else #error NOT IMPLEMENTED #endif @@ -1102,30 +1098,31 @@ int net_set_blocking(NETSOCKET sock) int net_tcp_listen(NETSOCKET sock, int backlog) { + int err = -1; if(sock.ipv4sock >= 0) - listen(sock.ipv4sock, backlog); + err = listen(sock.ipv4sock, backlog); if(sock.ipv6sock >= 0) - listen(sock.ipv6sock, backlog); - return 0; + err = listen(sock.ipv6sock, backlog); + return err; } int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a) { int s; socklen_t sockaddr_len; - struct sockaddr addr; *new_sock = invalid_socket; - sockaddr_len = sizeof(addr); - if(sock.ipv4sock >= 0) { - s = accept(sock.ipv4sock, &addr, &sockaddr_len); + struct sockaddr_in addr; + sockaddr_len = sizeof(addr); + s = accept(sock.ipv4sock, (struct sockaddr *)&addr, &sockaddr_len); + if (s != -1) { - sockaddr_to_netaddr(&addr, a); + sockaddr_to_netaddr((const struct sockaddr *)&addr, a); new_sock->type = NETTYPE_IPV4; new_sock->ipv4sock = s; return s; @@ -1134,18 +1131,21 @@ int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a) if(sock.ipv6sock >= 0) { - s = accept(sock.ipv6sock, &addr, &sockaddr_len); + struct sockaddr_in6 addr; + sockaddr_len = sizeof(addr); + s = accept(sock.ipv6sock, (struct sockaddr *)&addr, &sockaddr_len); + if (s != -1) { - sockaddr_to_netaddr(&addr, a); + sockaddr_to_netaddr((const struct sockaddr *)&addr, a); new_sock->type = NETTYPE_IPV6; new_sock->ipv6sock = s; return s; } } - return 0; + return -1; } int net_tcp_connect(NETSOCKET sock, const NETADDR *a) @@ -1164,7 +1164,7 @@ int net_tcp_connect(NETSOCKET sock, const NETADDR *a) return connect(sock.ipv6sock, (struct sockaddr *)&addr, sizeof(addr)); } - return 0; + return -1; } int net_tcp_connect_non_blocking(NETSOCKET sock, NETADDR bindaddr) @@ -1180,7 +1180,7 @@ int net_tcp_connect_non_blocking(NETSOCKET sock, NETADDR bindaddr) int net_tcp_send(NETSOCKET sock, const void *data, int size) { - int bytes = 0; + int bytes = -1; if(sock.ipv4sock >= 0) bytes = send((int)sock.ipv4sock, (const char*)data, size, 0); @@ -1192,7 +1192,7 @@ int net_tcp_send(NETSOCKET sock, const void *data, int size) int net_tcp_recv(NETSOCKET sock, void *data, int maxsize) { - int bytes = 0; + int bytes = -1; if(sock.ipv4sock >= 0) bytes = recv((int)sock.ipv4sock, (char*)data, maxsize, 0); @@ -1209,12 +1209,20 @@ int net_tcp_close(NETSOCKET sock) int net_errno() { +#if defined(CONF_FAMILY_WINDOWS) + return WSAGetLastError(); +#else return errno; +#endif } int net_would_block() { +#if defined(CONF_FAMILY_WINDOWS) + return net_errno() == WSAEWOULDBLOCK; +#else return net_errno() == EWOULDBLOCK; +#endif } int net_init() diff --git a/src/engine/console.h b/src/engine/console.h index 7c39cf49..5d3f2811 100644 --- a/src/engine/console.h +++ b/src/engine/console.h @@ -23,6 +23,8 @@ public: TEMPCMD_NAME_LENGTH=32, TEMPCMD_HELP_LENGTH=64, TEMPCMD_PARAMS_LENGTH=16, + + MAX_PRINT_CB=4, }; // TODO: rework this interface to reduce the amount of virtual calls @@ -79,7 +81,8 @@ public: virtual void ExecuteLineStroked(int Stroke, const char *pStr) = 0; virtual void ExecuteFile(const char *pFilename) = 0; - virtual void RegisterPrintCallback(FPrintCallback pfnPrintCallback, void *pUserData) = 0; + virtual int RegisterPrintCallback(int OutputLevel, FPrintCallback pfnPrintCallback, void *pUserData) = 0; + virtual void SetPrintOutputLevel(int Index, int OutputLevel) = 0; virtual void Print(int Level, const char *pFrom, const char *pStr) = 0; virtual void SetAccessLevel(int AccessLevel) = 0; diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 8e151035..ee7de31b 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -317,15 +318,8 @@ int CServer::Init() m_aClients[i].m_Snapshots.Init(); } - for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) - { - m_aEconClients[i].m_State = CEconClient::STATE_EMPTY; - } - m_CurrentGameTick = 0; - m_UseEcon = 0; - return 0; } @@ -618,30 +612,6 @@ int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser) return 0; } -int CServer::NewConsoleClientCallback(int EconID, void *pUser) -{ - CServer *pThis = (CServer *)pUser; - pThis->m_aEconClients[EconID].m_State = CEconClient::STATE_CONNECTED; - pThis->m_NetConsole.SetTimeout(EconID, g_Config.m_SvEconAuthTimeout); - return 0; -} - -int CServer::DelConsoleClientCallback(int EconID, const char *pReason, void *pUser) -{ - CServer *pThis = (CServer *)pUser; - - NETADDR Addr = pThis->m_NetConsole.ClientAddr(EconID); - char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "econ client dropped. eid=%d addr=%s reason='%s'", EconID, aAddrStr, pReason); - pThis->Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBuf); - - pThis->m_aEconClients[EconID].m_State = CEconClient::STATE_EMPTY; - return 0; -} - - void CServer::SendMap(int ClientID) { CMsgPacker Msg(NETMSG_MAP_CHANGE); @@ -664,12 +634,7 @@ void CServer::SendRconLine(int ClientID, const char *pLine) SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); } -void CServer::SendEconLine(int EconID, const char *pLine) -{ - m_NetConsole.Send(EconID, pLine); -} - -void CServer::SendConsoleLineAuthed(const char *pLine, void *pUser) +void CServer::SendRconLineAuthed(const char *pLine, void *pUser) { CServer *pThis = (CServer *)pUser; static volatile int ReentryGuard = 0; @@ -684,15 +649,6 @@ void CServer::SendConsoleLineAuthed(const char *pLine, void *pUser) pThis->SendRconLine(i, pLine); } - if(pThis->m_UseEcon) - { - for(i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) - { - if(pThis->m_aEconClients[i].m_State == CEconClient::STATE_AUTHED) - pThis->SendEconLine(i, pLine); - } - } - ReentryGuard--; } @@ -1130,46 +1086,7 @@ void CServer::PumpNetwork() ProcessClientPacket(&Packet); } - if(m_UseEcon) - EconPumpNetwork(); -} - -void CServer::EconPumpNetwork() -{ - m_NetConsole.Update(); - - char aBuf[NET_MAX_PACKETSIZE]; - int EconID; - - while(m_NetConsole.Recv(aBuf, sizeof(aBuf) - 1, &EconID)) - { - dbg_assert(m_aEconClients[EconID].m_State != CEconClient::STATE_EMPTY, "got message from empty slot"); - if(m_aEconClients[EconID].m_State == CEconClient::STATE_CONNECTED) - { - if(str_comp(aBuf, g_Config.m_SvRconPassword) == 0) - { - m_aEconClients[EconID].m_State = CEconClient::STATE_AUTHED; - m_NetConsole.Send(EconID, "Authentication successful. Remote console access granted."); - m_NetConsole.SetTimeout(EconID, g_Config.m_SvEconTimeout); - - str_format(aBuf, sizeof(aBuf), "EconID=%d authed", EconID); - Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf); - } - else - { - m_NetConsole.Send(EconID, "Wrong password"); - } - } - else if(m_aEconClients[EconID].m_State == CEconClient::STATE_AUTHED) - { - char aFormatted[256]; - str_format(aFormatted, sizeof(aBuf), "eid=%d cmd='%s'", EconID, aBuf); - Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aFormatted); - m_RconClientID = EconID; - Console()->ExecuteLine(aBuf); - m_RconClientID = -1; - } - } + m_Econ.Update(); } char *CServer::GetMapName() @@ -1244,7 +1161,7 @@ int CServer::Run() m_pStorage = Kernel()->RequestInterface(); // - Console()->RegisterPrintCallback(SendConsoleLineAuthed, this); + m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_ConsoleOutputLevel, SendRconLineAuthed, this); // load map if(!LoadMap(g_Config.m_SvMap)) @@ -1275,30 +1192,7 @@ int CServer::Run() m_NetServer.SetCallbacks(NewClientCallback, DelClientCallback, this); - if(g_Config.m_SvEconPort && g_Config.m_SvRconPassword[0]) - { - dbg_msg("econ", "binding econ to %s:%d", g_Config.m_SvEconBindaddr, g_Config.m_SvEconPort); - if(g_Config.m_SvEconBindaddr[0] && net_host_lookup(g_Config.m_SvEconBindaddr, &BindAddr, NETTYPE_ALL) == 0) - { - BindAddr.port = g_Config.m_SvEconPort; - } - else - { - mem_zero(&BindAddr, sizeof(BindAddr)); - BindAddr.type = NETTYPE_ALL; - BindAddr.port = g_Config.m_SvEconPort; - } - - if(m_NetConsole.Open(BindAddr, 0)) - { - m_NetConsole.SetCallbacks(NewConsoleClientCallback, DelConsoleClientCallback, this); - m_UseEcon = 1; - } - else - { - dbg_msg("econ", "couldn't open econ socket. port might already be in use"); - } - } + m_Econ.Init(Console()); char aBuf[256]; str_format(aBuf, sizeof(aBuf), "server name is '%s'", g_Config.m_SvName); @@ -1694,6 +1588,16 @@ void CServer::ConchainModCommandUpdate(IConsole::IResult *pResult, void *pUserDa pfnCallback(pResult, pCallbackUserData); } +void CServer::ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) +{ + pfnCallback(pResult, pCallbackUserData); + if(pResult->NumArguments() == 1) + { + CServer *pThis = static_cast(pUserData); + pThis->Console()->SetPrintOutputLevel(pThis->m_PrintCBIndex, pResult->GetInteger(0)); + } +} + void CServer::RegisterCommands() { m_pConsole = Kernel()->RequestInterface(); @@ -1715,6 +1619,7 @@ void CServer::RegisterCommands() Console()->Chain("sv_max_clients_per_ip", ConchainMaxclientsperipUpdate, this); Console()->Chain("mod_command", ConchainModCommandUpdate, this); + Console()->Chain("console_output_level", ConchainConsoleOutputLevelUpdate, this); } diff --git a/src/engine/server/server.h b/src/engine/server/server.h index d744b9ff..4e575055 100644 --- a/src/engine/server/server.h +++ b/src/engine/server/server.h @@ -109,26 +109,11 @@ public: CClient m_aClients[MAX_CLIENTS]; - class CEconClient - { - public: - enum - { - STATE_EMPTY=0, - STATE_CONNECTED, - STATE_AUTHED - }; - - int m_State; - }; - - CEconClient m_aEconClients[NET_MAX_CONSOLE_CLIENTS]; - CSnapshotDelta m_SnapshotDelta; CSnapshotBuilder m_SnapshotBuilder; CSnapIDPool m_IDPool; CNetServer m_NetServer; - CNetConsole m_NetConsole; + CEcon m_Econ; IEngineMap *m_pMap; @@ -138,8 +123,7 @@ public: int m_MapReload; int m_RconClientID; int m_RconAuthLevel; - - int m_UseEcon; + int m_PrintCBIndex; int64 m_Lastheartbeat; //static NETADDR4 master_server; @@ -186,14 +170,10 @@ public: static int NewClientCallback(int ClientID, void *pUser); static int DelClientCallback(int ClientID, const char *pReason, void *pUser); - static int NewConsoleClientCallback(int EconID, void *pUser); - static int DelConsoleClientCallback(int EconID, const char *pReason, void *pUser); - void SendMap(int ClientID); void SendConnectionReady(int ClientID); void SendRconLine(int ClientID, const char *pLine); - void SendEconLine(int EconID, const char *pLine); - static void SendConsoleLineAuthed(const char *pLine, void *pUser); + static void SendRconLineAuthed(const char *pLine, void *pUser); void SendRconCmdAdd(const IConsole::CCommandInfo *pCommandInfo, int ClientID); void SendRconCmdRem(const IConsole::CCommandInfo *pCommandInfo, int ClientID); @@ -207,8 +187,6 @@ public: int BanAdd(NETADDR Addr, int Seconds, const char *pReason); int BanRemove(NETADDR Addr); - void EconPumpNetwork(); - void PumpNetwork(); char *GetMapName(); @@ -229,6 +207,7 @@ public: 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); + static void ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); void RegisterCommands(); diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index fd318a7d..cb8f5f15 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -86,10 +86,12 @@ MACRO_CONFIG_STR(SvRconPassword, sv_rcon_password, 32, "", CFGFLAG_SERVER, "Remo MACRO_CONFIG_STR(SvRconModPassword, sv_rcon_mod_password, 32, "", CFGFLAG_SERVER, "Remote console password for moderators (limited access)") MACRO_CONFIG_INT(SvRconMaxTries, sv_rcon_max_tries, 3, 0, 100, CFGFLAG_SERVER, "Maximum number of tries for remote console authentication") MACRO_CONFIG_INT(SvRconBantime, sv_rcon_bantime, 5, 0, 1440, CFGFLAG_SERVER, "The time a client gets banned if remote console authentication fails. 0 makes it just use kick") -MACRO_CONFIG_STR(SvEconBindaddr, sv_econ_bindaddr, 128, "localhost", CFGFLAG_SERVER, "Address to bind the external console to. Anything but 'localhost' is dangerous") -MACRO_CONFIG_INT(SvEconPort, sv_econ_port, 0, 0, 0, CFGFLAG_SERVER, "Port to use for the external console") -MACRO_CONFIG_INT(SvEconAuthTimeout, sv_econ_auth_timeout, 30, 1, 120, CFGFLAG_SERVER, "Time in seconds before the the econ authentification times out") -MACRO_CONFIG_INT(SvEconTimeout, sv_econ_timeout, 300, 1, 3600, CFGFLAG_SERVER, "Time in seconds before the econ connection times out") + +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(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_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") diff --git a/src/engine/shared/console.cpp b/src/engine/shared/console.cpp index 847fb140..e4cb1991 100644 --- a/src/engine/shared/console.cpp +++ b/src/engine/shared/console.cpp @@ -173,20 +173,34 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat) return Error; } -void CConsole::RegisterPrintCallback(FPrintCallback pfnPrintCallback, void *pUserData) +int CConsole::RegisterPrintCallback(int OutputLevel, FPrintCallback pfnPrintCallback, void *pUserData) { - m_pfnPrintCallback = pfnPrintCallback; - m_pPrintCallbackUserdata = pUserData; + if(m_NumPrintCB == MAX_PRINT_CB) + return -1; + + m_aPrintCB[m_NumPrintCB].m_OutputLevel = clamp(OutputLevel, (int)(OUTPUT_LEVEL_STANDARD), (int)(OUTPUT_LEVEL_DEBUG)); + m_aPrintCB[m_NumPrintCB].m_pfnPrintCallback = pfnPrintCallback; + m_aPrintCB[m_NumPrintCB].m_pPrintCallbackUserdata = pUserData; + return m_NumPrintCB++; +} + +void CConsole::SetPrintOutputLevel(int Index, int OutputLevel) +{ + if(Index >= 0 && Index < MAX_PRINT_CB) + m_aPrintCB[Index].m_OutputLevel = clamp(OutputLevel, (int)(OUTPUT_LEVEL_STANDARD), (int)(OUTPUT_LEVEL_DEBUG)); } void CConsole::Print(int Level, const char *pFrom, const char *pStr) { dbg_msg(pFrom ,"%s", pStr); - if(Level <= g_Config.m_ConsoleOutputLevel && m_pfnPrintCallback) + for(int i = 0; i < m_NumPrintCB; ++i) { - char aBuf[1024]; - str_format(aBuf, sizeof(aBuf), "[%s]: %s", pFrom, pStr); - m_pfnPrintCallback(aBuf, m_pPrintCallbackUserdata); + if(Level <= m_aPrintCB[i].m_OutputLevel && m_aPrintCB[i].m_pfnPrintCallback) + { + char aBuf[1024]; + str_format(aBuf, sizeof(aBuf), "[%s]: %s", pFrom, pStr); + m_aPrintCB[i].m_pfnPrintCallback(aBuf, m_aPrintCB[i].m_pPrintCallbackUserdata); + } } } @@ -562,8 +576,8 @@ CConsole::CConsole(int FlagMask) m_ExecutionQueue.Reset(); m_pFirstCommand = 0; m_pFirstExec = 0; - m_pPrintCallbackUserdata = 0; - m_pfnPrintCallback = 0; + mem_zero(m_aPrintCB, sizeof(m_aPrintCB)); + m_NumPrintCB = 0; m_pStorage = 0; diff --git a/src/engine/shared/console.h b/src/engine/shared/console.h index b29f3202..6989c696 100644 --- a/src/engine/shared/console.h +++ b/src/engine/shared/console.h @@ -60,8 +60,13 @@ class CConsole : public IConsole void ExecuteFileRecurse(const char *pFilename); void ExecuteLineStroked(int Stroke, const char *pStr); - FPrintCallback m_pfnPrintCallback; - void *m_pPrintCallbackUserdata; + struct + { + int m_OutputLevel; + FPrintCallback m_pfnPrintCallback; + void *m_pPrintCallbackUserdata; + } m_aPrintCB[MAX_PRINT_CB]; + int m_NumPrintCB; enum { @@ -167,7 +172,8 @@ public: virtual void ExecuteLine(const char *pStr); virtual void ExecuteFile(const char *pFilename); - virtual void RegisterPrintCallback(FPrintCallback pfnPrintCallback, void *pUserData); + virtual int RegisterPrintCallback(int OutputLevel, FPrintCallback pfnPrintCallback, void *pUserData); + virtual void SetPrintOutputLevel(int Index, int OutputLevel); virtual void Print(int Level, const char *pFrom, const char *pStr); void SetAccessLevel(int AccessLevel) { m_AccessLevel = clamp(AccessLevel, (int)(ACCESS_LEVEL_ADMIN), (int)(ACCESS_LEVEL_MOD)); } 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 +#include + +#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(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(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); +} diff --git a/src/engine/shared/econ.h b/src/engine/shared/econ.h new file mode 100644 index 00000000..33b23ea6 --- /dev/null +++ b/src/engine/shared/econ.h @@ -0,0 +1,43 @@ +#ifndef ENGINE_SHARED_ECON_H +#define ENGINE_SHARED_ECON_H + +#include "network.h" + +class CEcon +{ + class CClient + { + public: + enum + { + STATE_EMPTY=0, + STATE_CONNECTED, + STATE_AUTHED, + }; + + int m_State; + int64 m_TimeConnected; + }; + CClient m_aClients[NET_MAX_CONSOLE_CLIENTS]; + + IConsole *m_pConsole; + CNetConsole m_NetConsole; + + bool m_Ready; + int m_PrintCBIndex; + + static void SendLineCB(const char *pLine, void *pUserData); + static void ConchainEconOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); + + static int NewClientCallback(int ClientID, void *pUser); + static int DelClientCallback(int ClientID, const char *pReason, void *pUser); + +public: + IConsole *Console() { return m_pConsole; } + + void Init(IConsole *pConsole); + void Update(); + void Send(int ClientID, const char *pLine); +}; + +#endif diff --git a/src/engine/shared/network.h b/src/engine/shared/network.h index d0b78d05..94e2824c 100644 --- a/src/engine/shared/network.h +++ b/src/engine/shared/network.h @@ -49,7 +49,7 @@ enum NET_MAX_CHUNKHEADERSIZE = 5, NET_PACKETHEADERSIZE = 3, NET_MAX_CLIENTS = 16, - NET_MAX_CONSOLE_CLIENTS = 16, + NET_MAX_CONSOLE_CLIENTS = 4, NET_MAX_SEQUENCE = 1<<10, NET_SEQUENCE_MASK = NET_MAX_SEQUENCE-1, @@ -196,32 +196,27 @@ public: class CConsoleNetConnection { private: - unsigned m_State; + int m_State; NETADDR m_PeerAddr; NETSOCKET m_Socket; char m_aBuffer[NET_MAX_PACKETSIZE]; - char *m_pBufferPos; + int m_BufferOffset; char m_aErrorString[256]; - int m_Timeout; - int64 m_LastRecvTime; + bool m_LineEndingDetected; + char m_aLineEnding[3]; public: - void Init(NETSOCKET Socket); void Init(NETSOCKET Socket, const NETADDR *pAddr); - int Connect(const NETADDR *pAddr); void Disconnect(const char *pReason); int State() const { return m_State; } NETADDR PeerAddress() const { return m_PeerAddr; } const char *ErrorString() const { return m_aErrorString; } - void SetTimeout(int Timeout) { m_Timeout = Timeout; } - int Timeout() const { return m_Timeout; } - void Reset(); int Update(); int Send(const char *pLine); @@ -337,7 +332,7 @@ private: }; NETSOCKET m_Socket; - CSlot m_aSlots[NET_MAX_CLIENTS]; + CSlot m_aSlots[NET_MAX_CONSOLE_CLIENTS]; NETFUNC_NEWCLIENT m_pfnNewClient; NETFUNC_DELCLIENT m_pfnDelClient; @@ -346,14 +341,13 @@ private: CNetRecvUnpacker m_RecvUnpacker; public: - int SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser); + void SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser); // bool Open(NETADDR BindAddr, int Flags); int Close(); // - int Broadcast(const char *pLine); int Recv(char *pLine, int MaxLength, int *pClientID = 0); int Send(int ClientID, const char *pLine); int Update(); @@ -362,11 +356,7 @@ public: int AcceptClient(NETSOCKET Socket, const NETADDR *pAddr); int Drop(int ClientID, const char *pReason); - // - void SetTimeout(int ClientID, int Timeout) { m_aSlots[ClientID].m_Connection.SetTimeout(Timeout); } - // status requests - int Timeout(int ClientID) { return m_aSlots[ClientID].m_Connection.Timeout(); } NETADDR ClientAddr(int ClientID) const { return m_aSlots[ClientID].m_Connection.PeerAddress(); } }; diff --git a/src/engine/shared/network_console.cpp b/src/engine/shared/network_console.cpp index 3e50a1ac..0cf2a718 100644 --- a/src/engine/shared/network_console.cpp +++ b/src/engine/shared/network_console.cpp @@ -9,25 +9,24 @@ bool CNetConsole::Open(NETADDR BindAddr, int Flags) mem_zero(this, sizeof(*this)); // open socket - m_Socket = net_tcp_create(&BindAddr); + m_Socket = net_tcp_create(BindAddr); if(!m_Socket.type) return false; if(net_tcp_listen(m_Socket, NET_MAX_CONSOLE_CLIENTS)) return false; - net_tcp_set_non_blocking(m_Socket); + net_set_non_blocking(m_Socket); - for(int i = 0; i < NET_MAX_CLIENTS; i++) - m_aSlots[i].m_Connection.Init(m_Socket); + for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) + m_aSlots[i].m_Connection.Reset(); return true; } -int CNetConsole::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser) +void CNetConsole::SetCallbacks(NETFUNC_NEWCLIENT pfnNewClient, NETFUNC_DELCLIENT pfnDelClient, void *pUser) { m_pfnNewClient = pfnNewClient; m_pfnDelClient = pfnDelClient; m_UserPtr = pUser; - return 0; } int CNetConsole::Close() @@ -38,11 +37,6 @@ int CNetConsole::Close() int CNetConsole::Drop(int ClientID, const char *pReason) { - NETADDR Addr = ClientAddr(ClientID); - - char aAddrStr[NETADDR_MAXSTRSIZE]; - net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr)); - if(m_pfnDelClient) m_pfnDelClient(ClientID, pReason, m_UserPtr); @@ -56,40 +50,39 @@ int CNetConsole::AcceptClient(NETSOCKET Socket, const NETADDR *pAddr) char aError[256] = { 0 }; int FreeSlot = -1; + // look for free slot or multiple client 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) { - NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress();; + NETADDR PeerAddr = m_aSlots[i].m_Connection.PeerAddress(); if(net_addr_comp(pAddr, &PeerAddr) == 0) { - str_copy(aError, "Only one client per IP allowed", sizeof(aError)); + str_copy(aError, "only one client per IP allowed", sizeof(aError)); break; } } } + // accept client if(!aError[0] && FreeSlot != -1) { m_aSlots[FreeSlot].m_Connection.Init(Socket, pAddr); if(m_pfnNewClient) m_pfnNewClient(FreeSlot, m_UserPtr); - return 1; + return 0; } + // reject client if(!aError[0]) - { - str_copy(aError, "No free slot available", sizeof(aError)); - } - - dbg_msg("netconsole", "refused client, reason=\"%s\"", aError); + str_copy(aError, "no free slot available", sizeof(aError)); net_tcp_send(Socket, aError, str_length(aError)); net_tcp_close(Socket); - return 0; + return -1; } int CNetConsole::Update() @@ -127,18 +120,10 @@ int CNetConsole::Recv(char *pLine, int MaxLength, int *pClientID) return 0; } -int CNetConsole::Broadcast(const char *pLine) -{ - for(int i = 0; i < NET_MAX_CONSOLE_CLIENTS; i++) - { - if(m_aSlots[i].m_Connection.State() == NET_CONNSTATE_ONLINE) - Send(i, pLine); - } - return 0; -} - int CNetConsole::Send(int ClientID, const char *pLine) { - return m_aSlots[ClientID].m_Connection.Send(pLine); + if(m_aSlots[ClientID].m_Connection.State() == NET_CONNSTATE_ONLINE) + return m_aSlots[ClientID].m_Connection.Send(pLine); + else + return -1; } - diff --git a/src/engine/shared/network_console_conn.cpp b/src/engine/shared/network_console_conn.cpp index 4dd971a6..75b581fa 100644 --- a/src/engine/shared/network_console_conn.cpp +++ b/src/engine/shared/network_console_conn.cpp @@ -1,7 +1,6 @@ /* (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 -#include "config.h" #include "network.h" void CConsoleNetConnection::Reset() @@ -10,9 +9,22 @@ void CConsoleNetConnection::Reset() mem_zero(&m_PeerAddr, sizeof(m_PeerAddr)); m_aErrorString[0] = 0; + m_Socket.type = NETTYPE_INVALID; + m_Socket.ipv4sock = -1; + m_Socket.ipv6sock = -1; m_aBuffer[0] = 0; - m_pBufferPos = 0; - m_Timeout = 0; + m_BufferOffset = 0; + + m_LineEndingDetected = false; + #if defined(CONF_FAMILY_WINDOWS) + m_aLineEnding[0] = '\r'; + m_aLineEnding[1] = '\n'; + m_aLineEnding[2] = 0; + #else + m_aLineEnding[0] = '\n'; + m_aLineEnding[1] = 0; + m_aLineEnding[2] = 0; + #endif } void CConsoleNetConnection::Init(NETSOCKET Socket, const NETADDR *pAddr) @@ -20,48 +32,19 @@ void CConsoleNetConnection::Init(NETSOCKET Socket, const NETADDR *pAddr) Reset(); m_Socket = Socket; - net_tcp_set_non_blocking(m_Socket); - - m_LastRecvTime = time_get(); + net_set_non_blocking(m_Socket); m_PeerAddr = *pAddr; m_State = NET_CONNSTATE_ONLINE; } -void CConsoleNetConnection::Init(NETSOCKET Socket) -{ - Reset(); - - m_Socket = Socket; - net_tcp_set_non_blocking(m_Socket); - - m_LastRecvTime = time_get(); -} - -int CConsoleNetConnection::Connect(const NETADDR *pAddr) -{ - if(State() != NET_CONNSTATE_OFFLINE) - return -1; - - // init connection - Reset(); - m_PeerAddr = *pAddr; - net_tcp_connect(m_Socket, pAddr); - m_State = NET_CONNSTATE_ONLINE; - return 0; -} - void CConsoleNetConnection::Disconnect(const char *pReason) { if(State() == NET_CONNSTATE_OFFLINE) return; - if(pReason) - { - char aBuf[sizeof(pReason) + 4]; - str_format(aBuf, sizeof(aBuf), "%s", pReason); - Send(aBuf); - } + if(pReason && pReason[0]) + Send(pReason); net_tcp_close(m_Socket); @@ -70,32 +53,20 @@ void CConsoleNetConnection::Disconnect(const char *pReason) int CConsoleNetConnection::Update() { - if(m_Timeout && time_get() > m_LastRecvTime + m_Timeout * time_freq()) - { - m_State = NET_CONNSTATE_ERROR; - str_copy(m_aErrorString, "timeout", sizeof(m_aErrorString)); - return -1; - } - if(State() == NET_CONNSTATE_ONLINE) { - char aBuf[NET_MAX_PACKETSIZE]; + if((int)(sizeof(m_aBuffer)) <= m_BufferOffset) + { + m_State = NET_CONNSTATE_ERROR; + str_copy(m_aErrorString, "too weak connection (out of buffer)", sizeof(m_aErrorString)); + return -1; + } - int Bytes = net_tcp_recv(m_Socket, aBuf, sizeof(aBuf) - 1); + int Bytes = net_tcp_recv(m_Socket, m_aBuffer+m_BufferOffset, (int)(sizeof(m_aBuffer))-m_BufferOffset); if(Bytes > 0) { - aBuf[Bytes - 1] = 0; - - if(!m_pBufferPos) - m_aBuffer[0] = 0; - else if(m_pBufferPos != m_aBuffer) - mem_move(m_pBufferPos, m_aBuffer, str_length(m_pBufferPos) + 1); // +1 for the \0 - m_pBufferPos = m_aBuffer; - - str_append(m_aBuffer, aBuf, sizeof(m_aBuffer)); - - m_LastRecvTime = time_get(); + m_BufferOffset += Bytes; } else if(Bytes < 0) { @@ -121,32 +92,59 @@ int CConsoleNetConnection::Recv(char *pLine, int MaxLength) { if(State() == NET_CONNSTATE_ONLINE) { - if(m_pBufferPos && *m_pBufferPos) + if(m_BufferOffset) { - char *pResult = m_pBufferPos; - - while(*m_pBufferPos && *m_pBufferPos != '\r' && *m_pBufferPos != '\n') - m_pBufferPos++; - - if(*m_pBufferPos) // haven't reached the end of the buffer? + // find message start + int StartOffset = 0; + while(m_aBuffer[StartOffset] == '\r' || m_aBuffer[StartOffset] == '\n') { - if(*m_pBufferPos == '\r' && *(m_pBufferPos + 1) == '\n') + // detect clients line ending format + if(!m_LineEndingDetected) { - *m_pBufferPos = 0; - m_pBufferPos += 2; + m_aLineEnding[0] = m_aBuffer[StartOffset]; + if(StartOffset+1 < m_BufferOffset && (m_aBuffer[StartOffset+1] == '\r' || m_aBuffer[StartOffset+1] == '\n') && + m_aBuffer[StartOffset] != m_aBuffer[StartOffset+1]) + m_aLineEnding[1] = m_aBuffer[StartOffset+1]; + m_LineEndingDetected = true; } - else + + if(++StartOffset >= m_BufferOffset) { - *m_pBufferPos = 0; - m_pBufferPos++; + m_BufferOffset = 0; + return 0; } } - else + + // find message end + int EndOffset = StartOffset; + while(m_aBuffer[EndOffset] != '\r' && m_aBuffer[EndOffset] != '\n') { - m_pBufferPos = 0; + if(++EndOffset >= m_BufferOffset) + { + if(StartOffset > 0) + { + mem_move(m_aBuffer, m_aBuffer+StartOffset, m_BufferOffset-StartOffset); + m_BufferOffset -= StartOffset; + } + return 0; + } } - str_copy(pLine, pResult, MaxLength); + // extract message and update buffer + if(MaxLength-1 < EndOffset-StartOffset) + { + if(StartOffset > 0) + { + mem_move(m_aBuffer, m_aBuffer+StartOffset, m_BufferOffset-StartOffset); + m_BufferOffset -= StartOffset; + } + return 0; + } + mem_copy(pLine, m_aBuffer+StartOffset, EndOffset-StartOffset); + pLine[EndOffset-StartOffset] = 0; + str_sanitize_cc(pLine); + mem_move(m_aBuffer, m_aBuffer+EndOffset, m_BufferOffset-EndOffset); + m_BufferOffset -= EndOffset; return 1; } } @@ -158,19 +156,31 @@ int CConsoleNetConnection::Send(const char *pLine) if(State() != NET_CONNSTATE_ONLINE) return -1; - int Length = str_length(pLine); char aBuf[1024]; - str_copy(aBuf, pLine, sizeof(aBuf) - 2); - aBuf[Length + 1] = '\n'; - aBuf[Length + 2] = '\0'; - - if(net_tcp_send(m_Socket, aBuf, Length + 2) < 0) + str_copy(aBuf, pLine, (int)(sizeof(aBuf))-2); + int Length = str_length(aBuf); + aBuf[Length] = m_aLineEnding[0]; + aBuf[Length+1] = m_aLineEnding[1]; + aBuf[Length+2] = m_aLineEnding[2]; + Length += 3; + const char *pData = aBuf; + + while(true) { - m_State = NET_CONNSTATE_ERROR; - str_copy(m_aErrorString, "Failed to send packet", sizeof(m_aErrorString)); - return -1; + int Send = net_tcp_send(m_Socket, pData, Length); + if(Send < 0) + { + m_State = NET_CONNSTATE_ERROR; + str_copy(m_aErrorString, "failed to send packet", sizeof(m_aErrorString)); + return -1; + } + + if(Send >= Length) + break; + + pData += Send; + Length -= Send; } return 0; } - diff --git a/src/game/client/components/console.cpp b/src/game/client/components/console.cpp index 9b16ce0d..f2e9e65d 100644 --- a/src/game/client/components/console.cpp +++ b/src/game/client/components/console.cpp @@ -662,6 +662,16 @@ void CGameConsole::ClientConsolePrintCallback(const char *pStr, void *pUserData) ((CGameConsole *)pUserData)->m_LocalConsole.PrintLine(pStr); } +void CGameConsole::ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) +{ + pfnCallback(pResult, pCallbackUserData); + if(pResult->NumArguments() == 1) + { + CGameConsole *pThis = static_cast(pUserData); + pThis->Console()->SetPrintOutputLevel(pThis->m_PrintCBIndex, pResult->GetInteger(0)); + } +} + void CGameConsole::PrintLine(int Type, const char *pLine) { if(Type == CONSOLETYPE_LOCAL) @@ -679,7 +689,7 @@ void CGameConsole::OnConsoleInit() m_pConsole = Kernel()->RequestInterface(); // - Console()->RegisterPrintCallback(ClientConsolePrintCallback, this); + m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_ConsoleOutputLevel, ClientConsolePrintCallback, this); Console()->Register("toggle_local_console", "", CFGFLAG_CLIENT, ConToggleLocalConsole, this, "Toggle local console"); Console()->Register("toggle_remote_console", "", CFGFLAG_CLIENT, ConToggleRemoteConsole, this, "Toggle remote console"); @@ -687,6 +697,8 @@ void CGameConsole::OnConsoleInit() Console()->Register("clear_remote_console", "", CFGFLAG_CLIENT, ConClearRemoteConsole, this, "Clear remote console"); Console()->Register("dump_local_console", "", CFGFLAG_CLIENT, ConDumpLocalConsole, this, "Dump local console"); Console()->Register("dump_remote_console", "", CFGFLAG_CLIENT, ConDumpRemoteConsole, this, "Dump remote console"); + + Console()->Chain("console_output_level", ConchainConsoleOutputLevelUpdate, this); } void CGameConsole::OnStateChange(int NewState, int OldState) diff --git a/src/game/client/components/console.h b/src/game/client/components/console.h index 326fb076..6bcc75a6 100644 --- a/src/game/client/components/console.h +++ b/src/game/client/components/console.h @@ -60,6 +60,7 @@ class CGameConsole : public CComponent CInstance *CurrentConsole(); float TimeNow(); + int m_PrintCBIndex; int m_ConsoleType; int m_ConsoleState; @@ -77,6 +78,7 @@ class CGameConsole : public CComponent static void ConClearRemoteConsole(IConsole::IResult *pResult, void *pUserData); static void ConDumpLocalConsole(IConsole::IResult *pResult, void *pUserData); static void ConDumpRemoteConsole(IConsole::IResult *pResult, void *pUserData); + static void ConchainConsoleOutputLevelUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); public: enum -- cgit 1.4.1 From 0f11cf014c7a53c20d4432ea26af41123f9f2436 Mon Sep 17 00:00:00 2001 From: oy Date: Sat, 30 Jul 2011 18:19:15 +0200 Subject: increased length for help string of temporary commands --- src/engine/console.h | 2 +- src/engine/server/server.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/engine/console.h') diff --git a/src/engine/console.h b/src/engine/console.h index 5d3f2811..0abf4ad2 100644 --- a/src/engine/console.h +++ b/src/engine/console.h @@ -21,7 +21,7 @@ public: ACCESS_LEVEL_MOD, TEMPCMD_NAME_LENGTH=32, - TEMPCMD_HELP_LENGTH=64, + TEMPCMD_HELP_LENGTH=96, TEMPCMD_PARAMS_LENGTH=16, MAX_PRINT_CB=4, diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index ee7de31b..46f87840 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -655,9 +655,9 @@ void CServer::SendRconLineAuthed(const char *pLine, void *pUser) void CServer::SendRconCmdAdd(const IConsole::CCommandInfo *pCommandInfo, int ClientID) { CMsgPacker Msg(NETMSG_RCON_CMD_ADD); - Msg.AddString(pCommandInfo->m_pName, 32); - Msg.AddString(pCommandInfo->m_pHelp, 64); - Msg.AddString(pCommandInfo->m_pParams, 16); + Msg.AddString(pCommandInfo->m_pName, IConsole::TEMPCMD_NAME_LENGTH); + Msg.AddString(pCommandInfo->m_pHelp, IConsole::TEMPCMD_HELP_LENGTH); + Msg.AddString(pCommandInfo->m_pParams, IConsole::TEMPCMD_PARAMS_LENGTH); SendMsgEx(&Msg, MSGFLAG_VITAL, ClientID, true); } -- cgit 1.4.1