diff options
| author | oy <Tom_Adams@web.de> | 2011-07-30 13:40:01 +0200 |
|---|---|---|
| committer | oy <Tom_Adams@web.de> | 2011-07-30 13:40:01 +0200 |
| commit | a0a62bcd70d1d8c0874d5ff52e443b5fb417854c (patch) | |
| tree | 00b0db83ea6bd25970b89bd465fa71d462e3cad2 /src/engine/shared | |
| parent | b0fdc4095988ed5bd8bda4b94ce35bc506f31653 (diff) | |
| download | zcatch-a0a62bcd70d1d8c0874d5ff52e443b5fb417854c.tar.gz zcatch-a0a62bcd70d1d8c0874d5ff52e443b5fb417854c.zip | |
fixed econ feature and tcp
Diffstat (limited to 'src/engine/shared')
| -rw-r--r-- | src/engine/shared/config_variables.h | 10 | ||||
| -rw-r--r-- | src/engine/shared/console.cpp | 32 | ||||
| -rw-r--r-- | src/engine/shared/console.h | 12 | ||||
| -rw-r--r-- | src/engine/shared/econ.cpp | 147 | ||||
| -rw-r--r-- | src/engine/shared/econ.h | 43 | ||||
| -rw-r--r-- | src/engine/shared/network.h | 24 | ||||
| -rw-r--r-- | src/engine/shared/network_console.cpp | 49 | ||||
| -rw-r--r-- | src/engine/shared/network_console_conn.cpp | 172 |
8 files changed, 343 insertions, 146 deletions
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 <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); +} 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 <base/system.h> -#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; } - |