diff --git a/r5dev/public/tier2/websocket.h b/r5dev/public/tier2/websocket.h index 0cec4a0c..0a38645f 100644 --- a/r5dev/public/tier2/websocket.h +++ b/r5dev/public/tier2/websocket.h @@ -1,8 +1,16 @@ -#ifndef TIER2_WEBSOCKETCREATOR_H -#define TIER2_WEBSOCKETCREATOR_H +//===========================================================================// +// +// Purpose: WebSocket implementation +// +//===========================================================================// +#ifndef TIER2_WEBSOCKET_H +#define TIER2_WEBSOCKET_H #define WEBSOCKET_DEFAULT_BUFFER_SIZE 1024 +//----------------------------------------------------------------------------- +// forward declarations +//----------------------------------------------------------------------------- struct ProtoWebSocketRefT; class CWebSocket @@ -10,17 +18,35 @@ class CWebSocket public: enum ConnState_e { + // The socket has to be created and setup CS_CREATE = 0, + // The socket connection is established CS_CONNECTED, + + // The socket is listening for data CS_LISTENING, + // The socket is destroyed and deallocated (if retries are set, the + // code will set the state to 'CS_RETRY' and reattempt to establish + // a connection up to ConnParams_s::maxRetries times CS_DESTROYED, + // The socket was destroyed and deallocated, and marked for a retry + // attempt CS_RETRY, + + // The socket was destroyed and deallocated, and is marked unavailable. + // the code will remove this connection from the list and no further + // attempts will be made CS_UNAVAIL }; + //------------------------------------------------------------------------- + // Connection parameters for the system & each individual connection, if + // these are changed, call CWebSocket::UpdateParams() to apply the new + // parameters on the system and each connection + //------------------------------------------------------------------------- struct ConnParams_s { ConnParams_s() @@ -34,15 +60,32 @@ public: laxSSL = 0; } + // Total amount of buffer size that could be queued up and sent int32_t bufSize; + + // Total amount of time between each connection attempt float retryTime; + + // Maximum number of retries + // NOTE: the initial attempt is not counted as a retry attempt; if this + // field is set to 5, then the code will perform 1 connection attempt + + // 5 retries before giving up and marking this connection as unavailable int32_t maxRetries; + // Total amount of time in seconds before the connection is timing out int32_t timeOut; + + // Time interval in seconds for the periodical keepalive pong message int32_t keepAlive; + + // Whether to validate the clients certificate, if this is set, no + // validation is performed int32_t laxSSL; }; + //------------------------------------------------------------------------- + // Represents an individual socket connection + //------------------------------------------------------------------------- struct ConnContext_s { ConnContext_s(const char* const addr) @@ -57,7 +100,7 @@ public: } bool Connect(const double queryTime, const ConnParams_s& params); - bool Status(const double queryTime); + bool Process(const double queryTime); void SetParams(const ConnParams_s& params); @@ -68,7 +111,7 @@ public: ProtoWebSocketRefT* webSocket; ConnState_e state; - int tryCount; + int tryCount; // Number of connection attempts double lastQueryTime; CUtlString address; @@ -79,13 +122,13 @@ public: bool Init(const char* const addressList, const ConnParams_s& params, const char*& initError); void Shutdown(); - bool SetupFromList(const char* const addressList); + bool UpdateAddressList(const char* const addressList); void UpdateParams(const ConnParams_s& params); void Update(); void DeleteUnavailable(); - void DestroyAll(); + void DisconnectAll(); void ReconnectAll(); void ClearAll(); @@ -98,4 +141,4 @@ private: CUtlVector m_addressList; }; -#endif // TIER2_WEBSOCKETCREATOR_H +#endif // TIER2_WEBSOCKET_H diff --git a/r5dev/tier2/websocket.cpp b/r5dev/tier2/websocket.cpp index f202e971..1c31ff5a 100644 --- a/r5dev/tier2/websocket.cpp +++ b/r5dev/tier2/websocket.cpp @@ -24,16 +24,18 @@ CWebSocket::CWebSocket() //----------------------------------------------------------------------------- bool CWebSocket::Init(const char* const addressList, const ConnParams_s& params, const char*& initError) { + Assert(addressList); + if (!NetConnStatus('open', 0, NULL, 0)) { initError = "Network connection module not initialized"; return false; } - if (!SetupFromList(addressList)) + if (!UpdateAddressList(addressList)) { initError = (*addressList) - ? "Failed to parse address list" + ? "Address list is invalid" : "Address list is empty"; return false; @@ -55,10 +57,12 @@ void CWebSocket::Shutdown() } //----------------------------------------------------------------------------- -// Purpose: setup connection list, returns false if connection list is empty +// Purpose: adds comma separated addresses to connection list, returns false if +// connection list is empty //----------------------------------------------------------------------------- -bool CWebSocket::SetupFromList(const char* const addressList) +bool CWebSocket::UpdateAddressList(const char* const addressList) { + Assert(addressList); const CUtlStringList addresses(addressList, ","); FOR_EACH_VEC(addresses, i) @@ -107,7 +111,7 @@ void CWebSocket::Update() if (conn.state == CS_CONNECTED || conn.state == CS_LISTENING) { - conn.Status(queryTime); + conn.Process(queryTime); continue; } @@ -138,20 +142,18 @@ void CWebSocket::DeleteUnavailable() FOR_EACH_VEC_BACK(m_addressList, i) { if (m_addressList[i].state == CS_UNAVAIL) - { m_addressList.FastRemove(i); - } } } //----------------------------------------------------------------------------- -// Purpose: destroy all connections +// Purpose: disconnect all connections //----------------------------------------------------------------------------- -void CWebSocket::DestroyAll() +void CWebSocket::DisconnectAll() { for (ConnContext_s& conn : m_addressList) { - conn.Destroy(); + conn.Disconnect(); } } @@ -171,7 +173,7 @@ void CWebSocket::ReconnectAll() //----------------------------------------------------------------------------- void CWebSocket::ClearAll() { - DestroyAll(); + DisconnectAll(); m_addressList.Purge(); } @@ -180,6 +182,9 @@ void CWebSocket::ClearAll() //----------------------------------------------------------------------------- void CWebSocket::SendData(const char* const dataBuf, const int32_t dataSize) { + Assert(dataBuf); + Assert(dataSize); + if (!IsInitialized()) return; @@ -189,9 +194,7 @@ void CWebSocket::SendData(const char* const dataBuf, const int32_t dataSize) continue; if (ProtoWebSocketSend(conn.webSocket, dataBuf, dataSize) < 0) - { conn.Destroy(); // Reattempt the connection for this socket - } } } @@ -244,7 +247,7 @@ bool CWebSocket::ConnContext_s::Connect(const double queryTime, const ConnParams //----------------------------------------------------------------------------- // Purpose: check the connection status and destroy if not connected (-1) //----------------------------------------------------------------------------- -bool CWebSocket::ConnContext_s::Status(const double queryTime) +bool CWebSocket::ConnContext_s::Process(const double queryTime) { const int32_t status = ProtoWebSocketStatus(webSocket, 'stat', NULL, 0); @@ -275,14 +278,10 @@ void CWebSocket::ConnContext_s::SetParams(const ConnParams_s& params) Assert(webSocket); if (params.timeOut > 0) - { ProtoWebSocketControl(webSocket, 'time', params.timeOut, 0, NULL); - } if (params.keepAlive > 0) - { ProtoWebSocketControl(webSocket, 'keep', params.keepAlive, 0, NULL); - } ProtoWebSocketControl(webSocket, 'ncrt', params.laxSSL, 0, NULL); ProtoWebSocketUpdate(webSocket);