diff --git a/src/net/Types.hpp b/src/net/Types.hpp index 7ea35e4..6c506b8 100644 --- a/src/net/Types.hpp +++ b/src/net/Types.hpp @@ -1286,6 +1286,21 @@ struct CHARACTER_INFO { uint8_t firstLogin; }; +struct CLIENT_NETSTATS { + uint32_t bytesSent; + uint32_t messagesSent; + uint32_t sendTimestamp; + uint32_t bytesReceived; + uint32_t messagesReceived; + uint32_t receivTimestamp; + uint32_t logTimestamp; + uint32_t unk1; + uint32_t unk2; + uint32_t unk3; + uint32_t unk4; +}; + + typedef void (*ENUMERATE_CHARACTERS_CALLBACK)(CHARACTER_INFO&, void*); diff --git a/src/net/connection/NetClient.cpp b/src/net/connection/NetClient.cpp index 6d67899..0adcca4 100644 --- a/src/net/connection/NetClient.cpp +++ b/src/net/connection/NetClient.cpp @@ -13,7 +13,8 @@ HPROPCONTEXT s_propContext; -int32_t NetClient::s_clientCount; +CLIENT_NETSTATS NetClient::s_stats = {}; +int32_t NetClient::s_clientCount = 0; void InitializePropContext() { if (PropGetSelectedContext() != s_propContext) { @@ -228,6 +229,30 @@ NETSTATE NetClient::GetState() { return this->m_netState; } +void NetClient::Ping() { + if (!this->m_serverConnection->m_encrypt) { + return; + } + + this->m_pingLock.Enter(); + this->m_pingSent = OsGetAsyncTimeMsPrecise(); + + CDataStore msg; + msg.Put(static_cast(CMSG_PING)); + msg.Put(++this->m_pingSequence); + if (this->m_netState == NS_CONNECTED) { + if (this->m_latencyEnd) { + msg.Put(this->m_latency[this->m_latencyEnd]); + } else { + msg.Put(static_cast(0)); + } + } + msg.Finalize(); + + this->m_pingLock.Leave(); + this->Send(&msg); +} + int32_t NetClient::HandleCantConnect() { // TODO return 1; @@ -273,7 +298,14 @@ int32_t NetClient::HandleDisconnect() { } void NetClient::HandleIdle() { - // TODO; + s_stats.unk1 = s_stats.bytesSent; + s_stats.unk2 = s_stats.bytesReceived; + s_stats.unk3 = s_stats.messagesSent; + s_stats.unk4 = s_stats.messagesReceived; + + if (OsGetAsyncTimeMsPrecise() - this->m_pingSent >= 30000) { + this->Ping(); + } } int32_t NetClient::Initialize() { @@ -310,7 +342,32 @@ void NetClient::PollEventQueue() { } void NetClient::PongHandler(WowConnection* conn, CDataStore* msg) { - // TODO + if (conn != this->m_serverConnection || this->m_suspended) { + conn->Disconnect(); + return; + } + + this->m_pingLock.Enter(); + + uint32_t sequence; + msg->Get(sequence); + + if (sequence == this->m_pingSequence) { + this->m_latency[this->m_latencyEnd++] = OsGetAsyncTimeMsPrecise() - this->m_pingSent; + + if (this->m_latencyEnd >= 16) { + this->m_latencyEnd = 0; + } + + if (this->m_latencyEnd == this->m_latencyStart) { + ++this->m_latencyStart; + if (this->m_latencyStart >= 16) + this->m_latencyStart = 0; + } + } else { + ConsolePrintf("Received pong with old sequence"); + } + this->m_pingLock.Leave(); } void NetClient::ProcessMessage(uint32_t timeReceived, CDataStore* msg, int32_t a4) { @@ -427,7 +484,11 @@ void NetClient::SetMessageHandler(NETMESSAGE msgId, MESSAGE_HANDLER handler, voi } void NetClient::WCCantConnect(WowConnection* conn, uint32_t timeStamp, NETCONNADDR* addr) { - // TODO + if (conn == this->m_redirectConnection) { + // TODO + } else if (conn == this->m_serverConnection) { + this->m_netEventQueue->AddEvent(EVENT_ID_NET_CANTCONNECT, conn, this, nullptr, 0); + } } void NetClient::WCConnected(WowConnection* conn, WowConnection* inbound, uint32_t timeStamp, const NETCONNADDR* addr) { diff --git a/src/net/connection/NetClient.hpp b/src/net/connection/NetClient.hpp index 03cf438..5bbdb48 100644 --- a/src/net/connection/NetClient.hpp +++ b/src/net/connection/NetClient.hpp @@ -70,6 +70,7 @@ class NetClient : public WowConnectionResponse { bool GetDelete(); const LoginData& GetLoginData(); NETSTATE GetState(); + void Ping(); void HandleIdle(); int32_t Initialize(); void PollEventQueue(); @@ -86,6 +87,7 @@ class NetClient : public WowConnectionResponse { private: // Static variables + static CLIENT_NETSTATS s_stats; static int32_t s_clientCount; // Member variables