chore: initial commit

This commit is contained in:
fallenoak 2023-01-02 13:17:18 -06:00
commit 70b00c5c38
No known key found for this signature in database
GPG key ID: 7628F8E61AEA070D
965 changed files with 264882 additions and 0 deletions

19
src/net/CMakeLists.txt Normal file
View file

@ -0,0 +1,19 @@
file(GLOB PRIVATE_SOURCES "*.cpp" "connection/*.cpp" "grunt/*.cpp" "login/*.cpp")
add_library(net STATIC
${PRIVATE_SOURCES}
)
target_include_directories(net
PRIVATE
${CMAKE_SOURCE_DIR}/src
)
target_link_libraries(net
PRIVATE
client
event
PUBLIC
common
storm
)

7
src/net/Connection.hpp Normal file
View file

@ -0,0 +1,7 @@
#ifndef NET_CONNECTION_HPP
#define NET_CONNECTION_HPP
#include "net/connection/ClientConnection.hpp"
#include "net/connection/RealmResponse.hpp"
#endif

7
src/net/Grunt.hpp Normal file
View file

@ -0,0 +1,7 @@
#ifndef NET_GRUNT_HPP
#define NET_GRUNT_HPP
#include "net/grunt/ClientLink.hpp"
#include "net/grunt/ClientResponse.hpp"
#endif

7
src/net/Login.hpp Normal file
View file

@ -0,0 +1,7 @@
#ifndef NET_LOGIN_HPP
#define NET_LOGIN_HPP
#include "net/login/BattlenetLogin.hpp"
#include "net/login/GruntLogin.hpp"
#endif

1221
src/net/Types.hpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,34 @@
#include "net/connection/ClientConnection.hpp"
#include "net/Login.hpp"
#include "client/ClientServices.hpp"
void ClientConnection::Cancel(int32_t errorCode) {
this->Cleanup();
this->m_statusResult = 0;
this->m_errorCode = errorCode;
this->m_statusComplete = 1;
// TODO
// LogConnectionStatus(this->m_statusCop, errorCode, 0);
}
void ClientConnection::Cleanup() {
if (this->m_cleanup) {
this->m_cleanup();
this->m_cleanup = nullptr;
}
}
void ClientConnection::Connect() {
// TODO
this->m_cleanup = nullptr;
this->m_statusCop = COP_CONNECT;
this->m_errorCode = 7;
this->m_statusComplete = 0;
// TODO
ClientServices::LoginConnection()->GetRealmList();
}

View file

@ -0,0 +1,27 @@
#ifndef NET_CONNECTION_CLIENT_CONNECTION_HPP
#define NET_CONNECTION_CLIENT_CONNECTION_HPP
#include "net/connection/RealmConnection.hpp"
#include "net/Types.hpp"
class RealmResponse;
class ClientConnection : public RealmConnection {
public:
// Member variables
int32_t m_statusComplete = 1;
int32_t m_statusResult = 1;
WOWCS_OPS m_statusCop = COP_NONE;
int32_t m_errorCode = 0;
void (*m_cleanup)() = nullptr;
// Member functions
ClientConnection(RealmResponse* realmResponse)
: RealmConnection(realmResponse)
{};
void Cancel(int32_t errorCode);
void Cleanup();
void Connect();
};
#endif

View file

@ -0,0 +1,66 @@
#include "net/connection/NetClient.hpp"
#include "net/connection/WowConnection.hpp"
#include <cstring>
#include <new>
#include <common/Prop.hpp>
#include <storm/Error.hpp>
HPROPCONTEXT s_propContext;
int32_t NetClient::s_clientCount;
void InitializePropContext() {
if (PropGetSelectedContext() != s_propContext) {
PropSelectContext(s_propContext);
}
}
int32_t NetClient::Initialize() {
STORM_ASSERT(this->m_netState == NS_UNINITIALIZED);
if (NetClient::s_clientCount == 0) {
s_propContext = PropGetSelectedContext();
if (!WowConnection::InitOsNet(nullptr, InitializePropContext, 1, false)) {
return 0;
}
}
NetClient::s_clientCount++;
auto queueMem = SMemAlloc(sizeof(NETEVENTQUEUE), __FILE__, __LINE__, 0x0);
auto queue = new (queueMem) NETEVENTQUEUE(this);
this->m_netEventQueue = queue;
memset(this->m_handlers, 0, sizeof(this->m_handlers));
memset(this->m_handlerParams, 0, sizeof(this->m_handlerParams));
auto connectionMem = SMemAlloc(sizeof(WowConnection), __FILE__, __LINE__, 0x0);
auto connection = new (connectionMem) WowConnection(this, nullptr);
this->m_serverConnection = connection;
this->m_netState = NS_INITIALIZED;
return 1;
}
void NetClient::SetMessageHandler(NETMESSAGE msgId, MESSAGE_HANDLER handler, void* param) {
this->m_handlers[msgId] = handler;
this->m_handlerParams[msgId] = param;
}
void NetClient::WCCantConnect(WowConnection* conn, uint32_t timeStamp, NETCONNADDR* addr) {
// TODO
}
void NetClient::WCConnected(WowConnection* conn, WowConnection* inbound, uint32_t timeStamp, const NETCONNADDR* addr) {
// TODO
}
void NetClient::WCDataReady(WowConnection* conn, uint32_t timeStamp, uint8_t* data, int32_t len) {
// TODO
}
void NetClient::WCDisconnected(WowConnection* conn, uint32_t timeStamp, NETCONNADDR* addr) {
// TODO
}

View file

@ -0,0 +1,56 @@
#ifndef NET_CONNECTION_NET_CLIENT_HPP
#define NET_CONNECTION_NET_CLIENT_HPP
#include "net/connection/WowConnectionResponse.hpp"
#include "net/Types.hpp"
#include <storm/List.hpp>
#include <storm/Thread.hpp>
#include <cstdint>
class CDataStore;
class NetClient;
class WowConnection;
typedef int32_t (*MESSAGE_HANDLER)(void* param, NETMESSAGE msgId, uint32_t time, CDataStore* msg);
class NETEVENTQUEUENODE : public TSLinkedNode<NETEVENTQUEUENODE> {
public:
};
class NETEVENTQUEUE {
public:
// Member variables
NetClient* m_client;
SCritSect m_critSect;
STORM_LIST(NETEVENTQUEUENODE) m_eventQueue;
// Member functions
NETEVENTQUEUE(NetClient* client)
: m_client(client)
{};
};
class NetClient : public WowConnectionResponse {
public:
// Static variables
static int32_t s_clientCount;
// Member variables
NETSTATE m_netState = NS_UNINITIALIZED;
MESSAGE_HANDLER m_handlers[NUM_MSG_TYPES];
void* m_handlerParams[NUM_MSG_TYPES];
NETEVENTQUEUE* m_netEventQueue = nullptr;
WowConnection* m_serverConnection = nullptr;
// Virtual member functions
virtual void WCConnected(WowConnection* conn, WowConnection* inbound, uint32_t timeStamp, const NETCONNADDR* addr);
virtual void WCCantConnect(WowConnection* conn, uint32_t timeStamp, NETCONNADDR* addr);
virtual void WCDisconnected(WowConnection* conn, uint32_t timeStamp, NETCONNADDR* addr);
virtual void WCDataReady(WowConnection* conn, uint32_t timeStamp, uint8_t* data, int32_t len);
// Member functions
int32_t Initialize();
void SetMessageHandler(NETMESSAGE msgId, MESSAGE_HANDLER handler, void* param);
};
#endif

View file

@ -0,0 +1,29 @@
#include "net/connection/RealmConnection.hpp"
#include "net/Types.hpp"
int32_t RealmConnection::MessageHandler(void* param, NETMESSAGE msgId, uint32_t time, CDataStore* msg) {
// TODO
return 0;
}
RealmConnection::RealmConnection(RealmResponse* realmResponse) {
this->m_realmResponse = realmResponse;
// TODO
this->Initialize();
this->SetMessageHandler(SMSG_AUTH_CHALLENGE, &RealmConnection::MessageHandler, this);
this->SetMessageHandler(SMSG_AUTH_RESPONSE, &RealmConnection::MessageHandler, this);
this->SetMessageHandler(SMSG_ADDON_INFO, &RealmConnection::MessageHandler, this);
this->SetMessageHandler(SMSG_ENUM_CHARACTERS_RESULT, &RealmConnection::MessageHandler, this);
this->SetMessageHandler(SMSG_CREATE_CHAR, &RealmConnection::MessageHandler, this);
this->SetMessageHandler(SMSG_CHARACTER_LOGIN_FAILED, &RealmConnection::MessageHandler, this);
this->SetMessageHandler(SMSG_LOGOUT_COMPLETE, &RealmConnection::MessageHandler, this);
this->SetMessageHandler(SMSG_LOGOUT_CANCEL_ACK, &RealmConnection::MessageHandler, this);
this->SetMessageHandler(SMSG_LOGOUT_RESPONSE, &RealmConnection::MessageHandler, this);
this->SetMessageHandler(SMSG_DELETE_CHAR, &RealmConnection::MessageHandler, this);
this->SetMessageHandler(SMSG_CACHE_VERSION, &RealmConnection::MessageHandler, this);
// TODO
}

View file

@ -0,0 +1,22 @@
#ifndef NET_CONNECTION_REALM_CONNECTION_HPP
#define NET_CONNECTION_REALM_CONNECTION_HPP
#include "net/connection/NetClient.hpp"
#include <cstdint>
class CDataStore;
class RealmResponse;
class RealmConnection : public NetClient {
public:
// Static functions
int32_t static MessageHandler(void* param, NETMESSAGE msgId, uint32_t time, CDataStore* msg);
// Member variables
RealmResponse* m_realmResponse;
// Member functions
RealmConnection(RealmResponse* realmResponse);
};
#endif

View file

@ -0,0 +1,8 @@
#ifndef NET_CONNECTION_REALM_RESPONSE_HPP
#define NET_CONNECTION_REALM_RESPONSE_HPP
class RealmResponse {
public:
};
#endif

View file

@ -0,0 +1,591 @@
#include "net/connection/WowConnection.hpp"
#include "net/connection/WowConnectionNet.hpp"
#include "net/connection/WowConnectionResponse.hpp"
#include <common/Time.hpp>
#include <storm/Error.hpp>
#include <storm/Memory.hpp>
#include <storm/String.hpp>
#include <storm/Thread.hpp>
#include <algorithm>
#include <new>
#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
#if defined(WHOA_SYSTEM_WIN)
#include <winsock2.h>
#endif
uint64_t WowConnection::s_countTotalBytes;
int32_t WowConnection::s_destroyed;
WowConnectionNet* WowConnection::s_network;
ATOMIC32 WowConnection::s_numWowConnections;
bool (*WowConnection::s_verifyAddr)(const NETADDR*);
int32_t WowConnection::CreateSocket() {
int32_t sock = socket(AF_INET, SOCK_STREAM, 0);
// TODO
return sock;
}
int32_t WowConnection::InitOsNet(bool (*fcn)(const NETADDR*), void (*threadinit)(), int32_t numThreads, bool useEngine) {
if (!WowConnection::s_network) {
// TODO s_usedSocketBits logic
// TODO WDataStore::StaticInitialize();
WowConnection::s_verifyAddr = fcn;
WowConnection::s_destroyed = 0;
numThreads = std::min(numThreads, 32);
auto networkMem = SMemAlloc(sizeof(WowConnectionNet), __FILE__, __LINE__, 0x0);
auto network = new (networkMem) WowConnectionNet(numThreads, threadinit);
WowConnection::s_network = network;
WowConnection::s_network->PlatformInit(useEngine);
WowConnection::s_network->Start();
}
return 1;
}
WowConnection::WowConnection(WowConnectionResponse* response, void (*func)(void)) {
// TODO
this->Init(response, func);
this->m_sock = -1;
}
WowConnection::WowConnection(int32_t sock, sockaddr_in* addr, WowConnectionResponse* response) {
// TODO
this->Init(response, nullptr);
// TODO
this->m_sock = sock;
this->m_connState = WOWC_CONNECTED;
}
void WowConnection::AcquireResponseRef() {
this->m_responseLock.Enter();
STORM_ASSERT(this->m_responseRef == 0 || this->GetState() == WOWC_LISTENING);
this->m_responseRef++;
this->m_responseRefThread = SGetCurrentThreadId();
this->m_responseLock.Leave();
}
void WowConnection::AddRef() {
SInterlockedIncrement(&this->m_refCount);
}
void WowConnection::CheckAccept() {
for (int32_t i = 0; i < 10000; i++) {
NETADDR addr;
socklen_t addrLen = sizeof(addr);
int32_t sock = accept(this->m_sock, reinterpret_cast<sockaddr*>(&addr), &addrLen);
if (sock < 0) {
break;
}
if (WowConnection::s_verifyAddr) {
NETADDR verifyAddr;
socklen_t verifyAddrLen = sizeof(verifyAddr);
getpeername(sock, reinterpret_cast<sockaddr*>(&verifyAddr), &verifyAddrLen);
if (!WowConnection::s_verifyAddr(&verifyAddr)) {
close(sock);
continue;
}
}
// TODO
// RegisterSocket(sock);
fcntl(sock, F_SETFL, O_NONBLOCK);
auto connMem = SMemAlloc(sizeof(WowConnection), __FILE__, __LINE__, 0x0);
auto conn = new (connMem) WowConnection(sock, reinterpret_cast<sockaddr_in*>(&addr), this->m_response);
conn->AddRef();
this->AddRef();
this->AcquireResponseRef();
this->m_lock.Leave();
if (this->m_response) {
this->m_response->WCConnected(this, conn, OsGetAsyncTimeMs(), &conn->m_peer);
}
WowConnection::s_network->Add(conn);
WowConnection::s_network->PlatformChangeState(conn, conn->GetState());
conn->Release();
this->m_lock.Enter();
this->ReleaseResponseRef();
this->Release();
}
}
void WowConnection::CheckConnect() {
int32_t err;
socklen_t errLen = sizeof(err);
if (getsockopt(this->m_sock, SOL_SOCKET, SO_ERROR, &err, &errLen)) {
return;
}
if (err) {
WowConnection::s_network->Remove(this);
WowConnection::CloseSocket(this->m_sock);
this->m_sock = -1;
this->SetState(WOWC_DISCONNECTED);
this->AddRef();
this->AcquireResponseRef();
this->m_lock.Leave();
if (this->m_response) {
this->m_response->WCCantConnect(this, OsGetAsyncTimeMsPrecise(), &this->m_peer);
}
} else {
this->SetState(WOWC_CONNECTED);
this->AddRef();
this->AcquireResponseRef();
this->m_lock.Leave();
socklen_t peerLen = sizeof(this->m_peer.peerAddr);
getpeername(this->m_sock, reinterpret_cast<sockaddr*>(&this->m_peer.peerAddr), &peerLen);
socklen_t selfLen = sizeof(this->m_peer.selfAddr);
getsockname(this->m_sock, reinterpret_cast<sockaddr*>(&this->m_peer.selfAddr), &selfLen);
if (this->m_response) {
this->m_response->WCConnected(this, nullptr, OsGetAsyncTimeMsPrecise(), &this->m_peer);
}
}
this->m_lock.Enter();
this->ReleaseResponseRef();
this->Release();
}
void WowConnection::CloseSocket(int32_t sock) {
#if defined(WHOA_SYSTEM_WIN)
closesocket(sock);
#endif
#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
close(sock);
#endif
if (sock >= 0) {
// TODO
}
}
bool WowConnection::Connect(char const* address, int32_t retryMs) {
char host[256];
auto port = SStrChr(address, ':');
if (port) {
this->m_connectPort = SStrToInt(port + 1);
size_t portIndex = port - address + 1;
portIndex = std::min(portIndex, sizeof(host));
SStrCopy(host, address, portIndex);
} else {
this->m_connectPort = 0;
SStrCopy(host, address, sizeof(host));
}
this->Connect(host, this->m_connectPort, retryMs);
return true;
}
bool WowConnection::Connect(char const* address, uint16_t port, int32_t retryMs) {
auto connectAddress = inet_addr(address);
if (connectAddress == -1 || connectAddress == 0) {
auto entry = gethostbyname(address);
if (entry) {
auto addrs = reinterpret_cast<uint8_t**>(entry->h_addr_list);
auto addr0 = addrs[0];
this->m_connectAddress = addr0[0]
| addr0[1] << 8
| addr0[2] << 16
| addr0[3] << 24;
} else {
this->m_connectAddress = 0;
}
} else {
this->m_connectAddress = connectAddress;
}
this->m_connectPort = port;
this->StartConnect();
return true;
}
void WowConnection::Disconnect() {
this->m_lock.Enter();
if (this->m_sock >= 0 && this->GetState() == WOWC_CONNECTED) {
this->m_connState = WOWC_DISCONNECTING;
if (WowConnection::s_network) {
WowConnection::s_network->PlatformChangeState(this, WOWC_CONNECTED);
}
}
this->m_lock.Leave();
}
void WowConnection::DoDisconnect() {
this->m_lock.Enter();
if (this->m_sock >= 0) {
WowConnection::s_network->Remove(this);
this->CloseSocket(this->m_sock);
}
this->SetState(WOWC_DISCONNECTED);
this->AddRef();
this->AcquireResponseRef();
this->m_lock.Leave();
if (this->m_response && this->m_sock >= 0) {
// TODO
// this->m_response->Vfunc4(this, OsGetAsyncTimeMsPrecise());
}
this->m_lock.Enter();
this->m_sock = -1;
this->ReleaseResponseRef();
this->m_lock.Leave();
this->Release();
}
void WowConnection::DoExceptions() {
this->AddRef();
this->m_lock.Enter();
if (this->GetState() == WOWC_CONNECTING) {
this->CheckConnect();
}
this->m_lock.Leave();
this->Release();
}
void WowConnection::DoMessageReads() {
// TODO
}
void WowConnection::DoReads() {
this->AddRef();
this->m_lock.Enter();
if (this->m_connState == WOWC_LISTENING) {
this->CheckAccept();
} else if (this->m_connState == WOWC_CONNECTED) {
if (this->m_type == WOWC_TYPE_STREAM) {
this->DoStreamReads();
} else {
this->DoMessageReads();
}
}
this->m_lock.Leave();
this->Release();
}
void WowConnection::DoStreamReads() {
uint32_t startTime = OsGetAsyncTimeMsPrecise();
uint8_t buf[4096];
uint32_t bytesRead;
while (1) {
while (1) {
bytesRead = recv(this->m_sock, buf, sizeof(buf), 0);
if (bytesRead >= 0) {
break;
}
#if defined(WHOA_SYSTEM_WIN)
if (WSAGetLastError() != WSAEINTR) {
break;
}
#elif defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
if (errno != EINTR) {
break;
}
#endif
}
if (bytesRead == 0) {
break;
}
this->AcquireResponseRef();
this->m_lock.Leave();
if (this->m_response) {
this->m_response->WCDataReady(this, OsGetAsyncTimeMs(), buf, bytesRead);
}
this->m_lock.Enter();
this->ReleaseResponseRef();
if (this->GetState() == WOWC_DISCONNECTING || (OsGetAsyncTimeMsPrecise() - startTime) >= 5) {
return;
}
}
bool shouldDisconnect = false;
#if defined(WHOA_SYSTEM_WIN)
shouldDisconnect = bytesRead >= 0 || WSAGetLastError() != WSAEAGAIN;
#elif defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
shouldDisconnect = bytesRead >= 0 || errno != EAGAIN;
#endif
if (shouldDisconnect) {
this->AcquireResponseRef();
WowConnection::s_network->Remove(this);
this->CloseSocket(this->m_sock);
this->SetState(WOWC_DISCONNECTED);
this->m_lock.Leave();
if (this->m_response && this->m_sock >= 0) {
this->m_response->WCDisconnected(this, OsGetAsyncTimeMs(), &this->m_peer);
}
this->m_lock.Enter();
this->m_sock = -1;
this->ReleaseResponseRef();
}
}
void WowConnection::DoWrites() {
this->AddRef();
this->m_lock.Enter();
if (this->m_connState == WOWC_CONNECTING) {
this->CheckConnect();
} else {
// TODO
}
// TODO
this->m_lock.Leave();
this->Release();
}
WOW_CONN_STATE WowConnection::GetState() {
return this->m_connState;
}
void WowConnection::Init(WowConnectionResponse* response, void (*func)(void)) {
SInterlockedIncrement(&WowConnection::s_numWowConnections);
this->m_refCount = 1;
this->m_responseRef = 0;
// TODO
this->m_connState = WOWC_UNINITIALIZED;
// TODO
this->m_response = response;
// TODO
this->m_connectAddress = 0;
this->m_connectPort = 0;
// TODO
this->m_serviceFlags = 0x0;
this->m_serviceCount = 0;
// TODO
this->SetState(WOWC_INITIALIZED);
this->m_type = WOWC_TYPE_MESSAGES;
}
void WowConnection::Release() {
if (SInterlockedDecrement(&this->m_refCount) <= 0) {
if (WowConnection::s_network) {
WowConnection::s_network->Delete(this);
} else {
// TODO SMemFree
delete this;
}
}
}
void WowConnection::ReleaseResponseRef() {
this->m_responseLock.Enter();
STORM_ASSERT(this->m_responseRef > 0);
this->m_responseRef--;
// TODO
// dwordD4 = (void *)this->dwordD4;
// if (dwordD4) {
// this->m_response = dwordD4;
// this->dwordD4 = 0;
// }
this->m_responseLock.Leave();
}
WC_SEND_RESULT WowConnection::SendRaw(uint8_t* data, int32_t len, bool a4) {
WowConnection::s_countTotalBytes += len;
this->m_lock.Enter();
// TODO
if (len > 0 && this->m_connState == WOWC_CONNECTED) {
STORM_ASSERT(this->m_sock >= 0);
#if defined (WHOA_SYSTEM_WIN)
// TODO
#elif defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
if (this->m_sendList.Head()) {
// TODO
} else {
auto written = write(this->m_sock, data, len);
if (written <= 0) {
// TODO
} else if (written == len) {
this->m_lock.Leave();
return WC_SEND_SENT;
}
}
#endif
}
this->m_lock.Leave();
return WC_SEND_ERROR;
}
void WowConnection::SetState(WOW_CONN_STATE state) {
WOW_CONN_STATE oldState = this->m_connState;
this->m_connState = state;
if (WowConnection::s_network) {
WowConnection::s_network->PlatformChangeState(this, oldState);
}
}
void WowConnection::SetType(WOWC_TYPE type) {
this->m_lock.Enter();
this->m_type = type;
this->m_lock.Leave();
}
void WowConnection::StartConnect() {
if (this->m_sock >= 0) {
if (this->m_netlink.IsLinked()) {
WowConnection::s_network->Remove(this);
}
this->CloseSocket(this->m_sock);
this->m_sock = -1;
}
this->m_lock.Enter();
this->m_sock = WowConnection::CreateSocket();
if (this->m_sock < 0) {
this->SetState(WOWC_ERROR);
this->m_lock.Leave();
return;
}
#if defined(WHOA_SYSTEM_MAC)
fcntl(this->m_sock, F_SETFL, O_NONBLOCK);
uint32_t opt = 1;
setsockopt(this->m_sock, SOL_SOCKET, 4130, &opt, sizeof(opt));
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(this->m_connectPort);
addr.sin_addr.s_addr = this->m_connectAddress;
if (!this->m_netlink.IsLinked()) {
WowConnection::s_network->Add(this);
}
this->SetState(WOWC_CONNECTING);
if (connect(this->m_sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) >= 0) {
this->m_lock.Leave();
return;
}
if (errno == EAGAIN || errno == EINTR || errno == EINPROGRESS) {
this->m_lock.Leave();
return;
}
WowConnection::s_network->Remove(this);
this->CloseSocket(this->m_sock);
this->m_sock = -1;
this->SetState(WOWC_ERROR);
this->m_lock.Leave();
#endif
}

View file

@ -0,0 +1,87 @@
#ifndef NET_CONNECTION_WOW_CONNECTION_HPP
#define NET_CONNECTION_WOW_CONNECTION_HPP
#include "net/Types.hpp"
#include <cstdint>
#include <storm/Atomic.hpp>
#include <storm/List.hpp>
#include <storm/Thread.hpp>
#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
#include <netinet/in.h>
#endif
#if defined(WHOA_SYSTEM_WIN)
#include <winsock2.h>
#endif
class WowConnectionNet;
class WowConnectionResponse;
class WowConnection {
public:
// Types
struct SENDNODE : public TSLinkedNode<SENDNODE> {
uint8_t* data;
uint32_t size;
uint32_t offset;
uint32_t datasize;
};
// Static variables
static uint64_t s_countTotalBytes;
static int32_t s_destroyed;
static WowConnectionNet* s_network;
static ATOMIC32 s_numWowConnections;
static bool (*s_verifyAddr)(const NETADDR*);
// Static functions
static int32_t CreateSocket();
static int32_t InitOsNet(bool (*fcn)(const NETADDR*), void (*threadinit)(), int32_t numThreads, bool useEngine);
// Member variables
ATOMIC32 m_refCount;
int32_t m_sock;
WOW_CONN_STATE m_connState;
WowConnectionResponse* m_response;
uint32_t m_connectAddress;
uint16_t m_connectPort;
NETCONNADDR m_peer;
SCritSect m_responseLock;
int32_t m_responseRef;
uintptr_t m_responseRefThread;
STORM_LIST(SENDNODE) m_sendList;
uint32_t m_serviceFlags;
TSLink<WowConnection> m_netlink;
SCritSect m_lock;
ATOMIC32 m_serviceCount;
WOWC_TYPE m_type;
// Member functions
WowConnection(WowConnectionResponse* response, void (*func)(void));
WowConnection(int32_t sock, sockaddr_in* addr, WowConnectionResponse* response);
void AcquireResponseRef();
void AddRef();
void CheckAccept();
void CheckConnect();
void CloseSocket(int32_t sock);
bool Connect(char const* address, int32_t retryMs);
bool Connect(char const* address, uint16_t port, int32_t retryMs);
void Disconnect();
void DoDisconnect();
void DoExceptions();
void DoMessageReads();
void DoReads();
void DoStreamReads();
void DoWrites();
WOW_CONN_STATE GetState();
void Init(WowConnectionResponse* response, void (*func)(void));
void Release();
void ReleaseResponseRef();
WC_SEND_RESULT SendRaw(uint8_t* data, int32_t len, bool a4);
void SetState(WOW_CONN_STATE state);
void SetType(WOWC_TYPE type);
void StartConnect();
};
#endif

View file

@ -0,0 +1,166 @@
#include "net/connection/WowConnectionNet.hpp"
#include "net/connection/WowConnection.hpp"
#include <storm/Atomic.hpp>
#include <storm/Error.hpp>
#include <storm/String.hpp>
#include <storm/Thread.hpp>
uint32_t MainProc(void* param) {
auto network = static_cast<WowConnectionNet*>(param);
network->Run();
return 0;
}
uint32_t WorkerProc(void* param) {
auto worker = static_cast<WowConnectionNet::Worker*>(param);
worker->owner->RunWorker(worker->id);
return 0;
}
void WowConnectionNet::Add(WowConnection* connection) {
this->m_connectionsLock.Enter();
if (!this->m_connections.IsLinked(connection)) {
this->m_connections.LinkToTail(connection);
this->PlatformAdd(connection);
}
this->m_connectionsLock.Leave();
}
void WowConnectionNet::Delete(WowConnection* connection) {
// TODO
}
void WowConnectionNet::Remove(WowConnection* connection) {
// TODO
}
void WowConnectionNet::Run() {
this->PlatformRun();
this->m_stopEvent.Set();
}
void WowConnectionNet::RunWorker(int32_t id) {
if (this->m_threadinit) {
this->m_threadinit();
}
this->m_workerSem.Signal(1);
auto& worker = this->m_workers[id];
while (true) {
do {
// TODO worker.time40 = OsGetAsyncTimeMsPrecise();
} while (worker.event.Wait(1000));
if (worker.quit) {
break;
}
auto serviceConn = worker.serviceConn;
auto serviceFlags = serviceConn->m_serviceFlags;
serviceConn->m_serviceFlags = 0;
this->Service(worker.serviceConn, serviceFlags);
worker.lock.Enter();
SInterlockedDecrement(&serviceConn->m_serviceCount);
serviceConn->Release();
worker.serviceConn = nullptr;
worker.lock.Leave();
this->m_workerSem.Signal(1);
this->PlatformWorkerReady();
}
}
void WowConnectionNet::Service(WowConnection* connection, uint32_t serviceFlags) {
while (serviceFlags) {
if (serviceFlags & 0x1) {
connection->DoWrites();
}
if (serviceFlags & 0x2) {
connection->DoReads();
}
if (serviceFlags & 0x4) {
connection->DoExceptions();
}
if (serviceFlags & 0x8) {
connection->DoDisconnect();
}
this->m_connectionsLock.Enter();
serviceFlags = connection->m_serviceFlags;
connection->m_serviceFlags = 0;
this->m_connectionsLock.Leave();
}
}
void WowConnectionNet::SignalWorker(WowConnection* connection, uint32_t flags) {
if (!this->m_workerSem.Wait(500)) {
connection->AddRef();
connection->m_serviceFlags = flags;
SInterlockedIncrement(&connection->m_serviceCount);
int32_t i = 0;
while (1) {
this->m_workers[i].lock.Enter();
if (!this->m_workers[i].serviceConn) {
break;
}
STORM_ASSERT(this->m_workers[i].serviceConn != connection);
this->m_workers[i].lock.Leave();
i++;
STORM_ASSERT(i < this->m_numWorkers);
}
this->m_workers[i].serviceConn = connection;
this->m_workers[i].lock.Leave();
this->m_workers[i].event.Set();
}
}
void WowConnectionNet::Start() {
for (int32_t i = 0; i < this->m_numWorkers; i++) {
auto worker = &this->m_workers[i];
worker->id = i;
worker->serviceConn = nullptr;
worker->quit = 0;
worker->owner = this;
// TODO worker.time40 = OsGetAsyncTimeMsPrecise();
char name[32];
SStrPrintf(name, sizeof(name), "NetThread %d", i);
SThread::Create(&WorkerProc, worker, worker->thread, name, 0);
}
char name[32];
SStrPrintf(name, sizeof(name), "Network");
// TODO BYTE1(this->dword8EC) = 0;
SThread::Create(&MainProc, this, this->m_thread, name, 0);
// TODO
// while (!BYTE1(this->dword8EC)) {
// OsSleep(100);
// }
}

View file

@ -0,0 +1,55 @@
#ifndef NET_CONNECTION_WOW_CONNECTION_NET_HPP
#define NET_CONNECTION_WOW_CONNECTION_NET_HPP
#include "net/connection/WowConnection.hpp"
#include <cstdint>
#include <storm/List.hpp>
#include <storm/Thread.hpp>
class WowConnectionNet {
public:
// Types
struct Worker {
WowConnectionNet* owner;
SThread thread;
int32_t id;
WowConnection* serviceConn;
SEvent event = SEvent(0, 0);
int8_t quit;
SCritSect lock;
};
// Member variables
SThread m_thread;
SEvent m_stopEvent = SEvent(1, 0);
uint8_t m_stop;
int32_t m_numWorkers;
Worker m_workers[32];
SCritSect m_connectionsLock;
STORM_EXPLICIT_LIST(WowConnection, m_netlink) m_connections;
SSemaphore m_workerSem;
void (*m_threadinit)();
// Member functions
WowConnectionNet(uint32_t numThreads, void (*threadinit)())
: m_workerSem(0, numThreads)
, m_numWorkers(numThreads)
, m_threadinit(threadinit)
, m_stop(0)
{};
void Add(WowConnection* connection);
void Delete(WowConnection* connection);
void PlatformAdd(WowConnection* connection);
void PlatformChangeState(WowConnection* connection, WOW_CONN_STATE state);
void PlatformInit(bool useEngine);
void PlatformRun();
void PlatformWorkerReady();
void Remove(WowConnection* connection);
void Run();
void RunWorker(int32_t id);
void Service(WowConnection* connection, uint32_t serviceFlags);
void SignalWorker(WowConnection* connection, uint32_t flags);
void Start();
};
#endif

View file

@ -0,0 +1,175 @@
#if defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX)
#include "net/connection/WowConnectionNet.hpp"
#include "net/connection/WowConnection.hpp"
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <unistd.h>
#include <storm/Array.hpp>
int32_t s_workerPipe[2];
void WowConnectionNet::PlatformAdd(WowConnection* connection) {
uint32_t on = 1;
setsockopt(connection->m_sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
char buf = '\1';
write(s_workerPipe[1], &buf, sizeof(buf));
}
void WowConnectionNet::PlatformChangeState(WowConnection* connection, WOW_CONN_STATE state) {
char buf = '\1';
write(s_workerPipe[1], &buf, sizeof(buf));
}
void WowConnectionNet::PlatformInit(bool useEngine) {
// TODO
}
void WowConnectionNet::PlatformRun() {
pipe(s_workerPipe);
if (fcntl(s_workerPipe[0], F_SETFL, O_NONBLOCK) < 0) {
perror("fcntl(worker pipe)");
}
TSGrowableArray<WowConnection*> connections;
char buf[25];
while (!this->m_stop) {
timeval timeout = { 30, 0 };
fd_set readFds = {};
fd_set writeFds = {};
fd_set errorFds = {};
readFds.fds_bits[s_workerPipe[0] >> 5] |= 1 << (s_workerPipe[0] & 0x1F);
auto fdCount = s_workerPipe[0];
int32_t v39 = 0;
int32_t v41 = 0;
this->m_connectionsLock.Enter();
for (auto connection = this->m_connections.Head(); connection; connection = this->m_connections.Link(connection)->Next()) {
if (connection->m_serviceCount) {
continue;
}
switch (connection->m_connState) {
case WOWC_CONNECTING: {
errorFds.fds_bits[connection->m_sock >> 5] |= 1 << (connection->m_sock & 0x1F);
writeFds.fds_bits[connection->m_sock >> 5] |= 1 << (connection->m_sock & 0x1F);
connections.Add(1, &connection);
connection->AddRef();
fdCount = std::max(fdCount, connection->m_sock);
break;
}
case WOWC_LISTENING: {
readFds.fds_bits[connection->m_sock >> 5] |= 1 << (connection->m_sock & 0x1F);
connections.Add(1, &connection);
connection->AddRef();
fdCount = std::max(fdCount, connection->m_sock);
break;
}
case WOWC_CONNECTED: {
readFds.fds_bits[connection->m_sock >> 5] |= 1 << (connection->m_sock & 0x1F);
errorFds.fds_bits[connection->m_sock >> 5] |= 1 << (connection->m_sock & 0x1F);
// TODO
connections.Add(1, &connection);
connection->AddRef();
fdCount = std::max(fdCount, connection->m_sock);
}
case WOWC_DISCONNECTING: {
// TODO
v41++;
connections.Add(1, &connection);
connection->AddRef();
break;
}
default: {
break;
}
}
}
this->m_connectionsLock.Leave();
if (v41 > 0) {
timeout = { 0, 0 };
}
if (connections.Count() > 0) {
// TODO
}
select(fdCount + 1, &readFds, &writeFds, &errorFds, &timeout);
auto v1 = s_workerPipe[0];
if (((1 << (s_workerPipe[0] & 0x1F)) & readFds.fds_bits[s_workerPipe[0] >> 5]) != 0) {
while (read(v1, buf, 1u) > 0) {
v1 = s_workerPipe[0];
}
}
for (int32_t i = 0; i < connections.Count(); i++) {
auto connection = connections[i];
uint32_t signalFlags = 0x0;
if (!(connection->m_sock & 0x80000000)) {
if (FD_ISSET(connection->m_sock, &writeFds)) {
signalFlags |= 0x1;
}
if (FD_ISSET(connection->m_sock, &readFds)) {
signalFlags |= 0x2;
}
if (FD_ISSET(connection->m_sock, &errorFds)) {
signalFlags |= 0x4;
}
}
if (connection->m_connState == WOWC_DISCONNECTING) {
signalFlags |= 0x8;
}
// TODO
// auto v15 = connection->dword10C;
// if (!(v15 & 1) && v15) {
// signalFlags |= 0x2;
// }
if (signalFlags) {
this->SignalWorker(connection, signalFlags);
}
connection->Release();
}
}
}
void WowConnectionNet::PlatformWorkerReady() {
char buf = '\1';
write(s_workerPipe[1], &buf, sizeof(buf));
}
#endif

View file

@ -0,0 +1,25 @@
#if defined(WHOA_SYSTEM_WIN)
#include "net/connection/WowConnectionNet.hpp"
void WowConnectionNet::PlatformAdd(WowConnection* connection) {
// TODO
}
void WowConnectionNet::PlatformChangeState(WowConnection* connection, WOW_CONN_STATE state) {
// TODO
}
void WowConnectionNet::PlatformInit(bool useEngine) {
// TODO
}
void WowConnectionNet::PlatformRun() {
// TODO
}
void WowConnectionNet::PlatformWorkerReady() {
// TODO
}
#endif

View file

@ -0,0 +1,17 @@
#ifndef NET_CONNECTION_WOW_CONNECTION_RESPONSE_HPP
#define NET_CONNECTION_WOW_CONNECTION_RESPONSE_HPP
#include "net/Types.hpp"
class WowConnection;
class WowConnectionResponse {
public:
// Virtual member functions
virtual void WCConnected(WowConnection* conn, WowConnection* inbound, uint32_t timeStamp, const NETCONNADDR* addr) = 0;
virtual void WCCantConnect(WowConnection* conn, uint32_t timeStamp, NETCONNADDR* addr) = 0;
virtual void WCDisconnected(WowConnection* conn, uint32_t timeStamp, NETCONNADDR* addr) {};
virtual void WCDataReady(WowConnection* conn, uint32_t timeStamp, uint8_t* data, int32_t len) {};
};
#endif

View file

@ -0,0 +1,165 @@
#include "net/grunt/ClientLink.hpp"
#include "net/connection/WowConnection.hpp"
#include "net/grunt/ClientResponse.hpp"
#include <new>
#include <common/DataStore.hpp>
#include <storm/Memory.hpp>
#include <storm/String.hpp>
Grunt::ClientLink::ClientLink(Grunt::ClientResponse& clientResponse) {
// TODO
this->m_clientResponse = &clientResponse;
this->SetState(0);
if (this->m_timer.m_thread.Valid()) {
this->m_interval = 100;
this->m_timer.Insert(*this);
}
}
void Grunt::ClientLink::Call() {
// TODO
// this->CheckExpired(false);
this->m_critSect.Enter();
if (this->m_state == 2) {
this->m_clientResponse->GetLogonMethod();
} else if (this->m_state == 6 && !this->m_clientResponse->OnlineIdle()) {
this->Disconnect();
}
this->m_critSect.Leave();
}
void Grunt::ClientLink::Connect(const char* a2) {
if (this->m_state) {
return;
}
this->SetState(1);
auto connectionMem = SMemAlloc(sizeof(WowConnection), __FILE__, __LINE__, 0x0);
auto connection = new (connectionMem) WowConnection(this, nullptr);
this->m_connection = connection;
this->m_connection->SetType(WOWC_TYPE_STREAM);
auto port = SStrChr(a2, ':');
if (port) {
this->m_connection->Connect(a2, 5000);
} else {
this->m_connection->Connect(a2, 3724, 5000);
}
}
void Grunt::ClientLink::Disconnect() {
this->m_critSect.Enter();
if (this->m_connection) {
this->m_connection->Disconnect();
}
this->m_critSect.Leave();
}
void Grunt::ClientLink::LogonNewSession(const Grunt::ClientLink::Logon& logon) {
this->SetState(3);
SStrCopy(this->m_accountName, logon.accountName, sizeof(this->m_accountName));
SStrUpper(this->m_accountName);
char* password = static_cast<char*>(alloca(SStrLen(logon.password) + 1));
SStrCopy(password, logon.password, STORM_MAX_STR);
SStrUpper(password);
static char accountNameUnDecorated[1280];
SStrCopy(accountNameUnDecorated, this->m_accountName, STORM_MAX_STR);
auto decoration = const_cast<char*>(SStrChr(accountNameUnDecorated, '#'));
if (decoration) {
*decoration = '\0';
}
// TODO SRP6_Client::BeginAuthentication
CDataStoreCache<1024> clientChallenge;
uint8_t opcode = 0;
clientChallenge.Put(opcode);
uint8_t protocol = 8;
clientChallenge.Put(protocol);
this->PackLogon(clientChallenge, logon);
clientChallenge.Finalize();
this->Send(clientChallenge);
}
void Grunt::ClientLink::PackLogon(CDataStore& msg, const Logon& logon) {
uint32_t startPos = msg.m_size;
uint16_t tmpSize = 0;
msg.Put(tmpSize);
msg.Put(logon.programID);
msg.Put(logon.version[0]);
msg.Put(logon.version[1]);
msg.Put(logon.version[2]);
msg.Put(logon.build);
msg.Put(logon.processorID);
msg.Put(logon.osID);
msg.Put(logon.locale);
msg.Put(logon.tz);
msg.Put(this->m_clientIP);
uint32_t accountNameLen = SStrLen(this->m_accountName);
msg.Put(accountNameLen);
msg.PutData(this->m_accountName, accountNameLen);
msg.Set(startPos, msg.m_size - startPos - 2);
}
void Grunt::ClientLink::Send(CDataStore& msg) {
this->m_critSect.Enter();
if (this->m_connection) {
void* data;
msg.GetDataInSitu(data, msg.m_size);
this->m_connection->SendRaw(static_cast<uint8_t*>(data), msg.m_size, false);
}
this->m_critSect.Leave();
}
void Grunt::ClientLink::SetState(int32_t state) {
this->m_critSect.Enter();
this->m_state = state;
this->m_critSect.Leave();
}
void Grunt::ClientLink::WCCantConnect(WowConnection* conn, uint32_t timeStamp, NETCONNADDR* addr) {
// TODO
}
void Grunt::ClientLink::WCConnected(WowConnection* conn, WowConnection* inbound, uint32_t timeStamp, const NETCONNADDR* addr) {
this->m_critSect.Enter();
this->SetState(2);
int32_t connected = this->m_clientResponse->Connected(addr->peerAddr);
// TODO
// this->m_clientIP = OsNetAddrGetAddress(&addr->selfAddr, 0);
this->m_critSect.Leave();
if (!connected) {
this->Disconnect();
}
}

View file

@ -0,0 +1,54 @@
#ifndef NET_GRUNT_CLIENT_LINK_HPP
#define NET_GRUNT_CLIENT_LINK_HPP
#include "net/grunt/Grunt.hpp"
#include "net/connection/WowConnectionResponse.hpp"
#include "net/grunt/Pending.hpp"
#include "net/grunt/Timer.hpp"
#include "net/Types.hpp"
#include <storm/Thread.hpp>
class CDataStore;
class WowConnection;
class Grunt::ClientLink : public WowConnectionResponse, Grunt::Pending, Grunt::Timer::Event {
public:
// Types
struct Logon {
const char* accountName;
const char* password;
uint32_t programID;
uint32_t processorID;
uint32_t osID;
uint8_t version[4];
uint16_t build;
uint16_t uint1A;
uint32_t locale;
uint32_t tz;
};
// Member variables
Grunt::Timer m_timer;
uint32_t m_clientIP = 0;
int32_t m_state;
SCritSect m_critSect;
WowConnection* m_connection = nullptr;
ClientResponse* m_clientResponse;
char m_accountName[1280];
// Virtual member functions
virtual void WCConnected(WowConnection* conn, WowConnection* inbound, uint32_t timeStamp, const NETCONNADDR* addr);
virtual void WCCantConnect(WowConnection* conn, uint32_t timeStamp, NETCONNADDR* addr);
virtual void Call();
// Member functions
ClientLink(Grunt::ClientResponse& clientResponse);
void Connect(const char* a2);
void Disconnect();
void LogonNewSession(const Logon& logon);
void PackLogon(CDataStore& msg, const Logon& logon);
void Send(CDataStore& msg);
void SetState(int32_t state);
};
#endif

View file

@ -0,0 +1,20 @@
#ifndef NET_GRUNT_CLIENT_RESPONSE_HPP
#define NET_GRUNT_CLIENT_RESPONSE_HPP
#include "net/grunt/Grunt.hpp"
#include "net/Types.hpp"
class LoginResponse;
class Grunt::ClientResponse {
public:
virtual bool Connected(const NETADDR& addr) = 0;
virtual bool OnlineIdle() = 0;
virtual void GetLogonMethod() = 0;
virtual void GetRealmList() = 0;
virtual void Logon(const char* a2, const char* a3) = 0;
virtual void Logoff() = 0;
virtual void Init(LoginResponse* loginResponse) = 0;
};
#endif

11
src/net/grunt/Grunt.hpp Normal file
View file

@ -0,0 +1,11 @@
#ifndef NET_GRUNT_GRUNT_HPP
#define NET_GRUNT_GRUNT_HPP
namespace Grunt {
class ClientLink;
class ClientResponse;
class Pending;
class Timer;
}
#endif

10
src/net/grunt/Pending.hpp Normal file
View file

@ -0,0 +1,10 @@
#ifndef NET_GRUNT_PENDING_HPP
#define NET_GRUNT_PENDING_HPP
#include "net/Grunt.hpp"
class Grunt::Pending {
public:
};
#endif

70
src/net/grunt/Timer.cpp Normal file
View file

@ -0,0 +1,70 @@
#include "net/grunt/Timer.hpp"
#include <common/Time.hpp>
uint32_t Grunt::Timer::ThreadProc(void* param) {
auto timer = static_cast<Timer*>(param);
while (true) {
auto timeout = timer->Pump();
if (timer->m_event.Wait(timeout) == 0) {
break;
}
}
return 1;
}
Grunt::Timer::Timer() {
SThread::Create(Grunt::Timer::ThreadProc, this, this->m_thread, "GruntTimerEvt", 0);
}
void Grunt::Timer::Insert(Grunt::Timer::Event& newEvent) {
this->m_critSect.Enter();
newEvent.m_schedTime = OsGetAsyncTimeMsPrecise() + newEvent.m_interval;
for (auto event = this->m_eventList.Head(); event; event = this->m_eventList.Link(event)->Next()) {
// Keep event listed sorted by scheduled time
if (newEvent.m_schedTime - event->m_schedTime < 0) {
this->m_eventList.LinkNode(&newEvent, 2, event);
this->m_critSect.Leave();
return;
}
}
this->m_eventList.LinkToTail(&newEvent);
this->m_critSect.Leave();
}
uint32_t Grunt::Timer::Pump() {
this->m_critSect.Enter();
auto* event = this->m_eventList.Head();
if (!event) {
this->m_critSect.Leave();
return 100;
}
int32_t timeUntilSched = event->m_schedTime - OsGetAsyncTimeMsPrecise();
if (timeUntilSched <= 0) {
this->m_eventList.UnlinkNode(event);
this->m_critSect.Leave();
event->Call();
this->Insert(*event);
return 100;
}
this->m_critSect.Leave();
return timeUntilSched;
}

37
src/net/grunt/Timer.hpp Normal file
View file

@ -0,0 +1,37 @@
#ifndef NET_GRUNT_TIMER_HPP
#define NET_GRUNT_TIMER_HPP
#include "net/grunt/Grunt.hpp"
#include "storm/List.hpp"
#include "storm/Thread.hpp"
class Grunt::Timer {
public:
// Types
class Event {
public:
// Member variables
TSLink<Event> m_link;
uint32_t m_schedTime;
uint32_t m_interval;
// Virtual methods
virtual void Call() = 0;
};
// Static functions
static uint32_t ThreadProc(void* param);
// Member variables
SEvent m_event = SEvent(0, 0);
SThread m_thread;
SCritSect m_critSect;
STORM_EXPLICIT_LIST(Event, m_link) m_eventList;
// Member functions
Timer();
void Insert(Event&);
uint32_t Pump();
};
#endif

View file

@ -0,0 +1,10 @@
#ifndef NET_LOGIN_BATTLENET_LOGIN_HPP
#define NET_LOGIN_BATTLENET_LOGIN_HPP
#include "net/login/Login.hpp"
class BattlenetLogin : public Login {
public:
};
#endif

View file

@ -0,0 +1,126 @@
#include "net/login/GruntLogin.hpp"
#include "net/grunt/ClientLink.hpp"
#include "net/login/LoginResponse.hpp"
#include <cstring>
#include <new>
#include <storm/Memory.hpp>
#include <storm/String.hpp>
GruntLogin::~GruntLogin() {
// TODO
}
bool GruntLogin::Connected(const NETADDR& addr) {
this->m_loggedOn = true;
this->m_loginResponse->m_loginState = LOGIN_STATE_15;
this->m_loginResponse->m_loginResult = LOGIN_OK;
char addrStr[32];
// TODO
// OsNetAddrToStr(addr, addrStr, sizeof(addrStr));
char stateStr[64];
// TODO
// SStrCopy(stateStr, g_LoginStateStringNames[LOGIN_STATE_15], sizeof(stateStr));
char resultStr[64];
// TODO
// SStrCopy(resultStr, g_LoginResultStringNames[LOGIN_OK], sizeof(resultStr));
// TODO
this->m_loginResponse->LoginServerStatus(LOGIN_STATE_15, LOGIN_OK, addrStr, stateStr, resultStr, 0);
return true;
}
void GruntLogin::GetLogonMethod() {
Grunt::ClientLink::Logon logon;
logon.accountName = nullptr;
logon.password = nullptr;
// TODO
// TODO Pull build info into something common
logon.version[0] = 3;
logon.version[1] = 3;
logon.version[2] = 5;
logon.build = 12340;
// TODO
if (this->IsReconnect()) {
// TODO
} else if (this->m_password) {
this->m_loginResponse->m_loginState = LOGIN_STATE_AUTHENTICATING;
this->m_loginResponse->m_loginResult = LOGIN_OK;
char stateStr[64];
// TODO
// SStrCopy(stateStr, g_LoginStateStringNames[LOGIN_STATE_AUTHENTICATING], sizeof(stateStr));
char resultStr[64];
// TODO
// SStrCopy(resultStr, g_LoginResultStringNames[LOGIN_OK], sizeof(resultStr));
this->m_loginResponse->LoginServerStatus(
LOGIN_STATE_AUTHENTICATING,
LOGIN_OK,
nullptr,
stateStr,
resultStr,
0
);
logon.password = this->m_password;
logon.accountName = this->m_accountName;
this->m_clientLink->LogonNewSession(logon);
auto passwordLen = SStrLen(this->m_password);
memset(this->m_password, 0, passwordLen);
SMemFree(this->m_password, __FILE__, __LINE__, 0);
this->m_password = nullptr;
}
}
void GruntLogin::GetRealmList() {
// TODO
}
void GruntLogin::Init(LoginResponse* loginResponse) {
this->m_loginResponse = loginResponse;
auto clientLinkMem = SMemAlloc(sizeof(Grunt::ClientLink), __FILE__, __LINE__, 0x0);
auto clientLink = new (clientLinkMem) Grunt::ClientLink(*this);
this->m_clientLink = clientLink;
}
void GruntLogin::Logoff() {
// TODO
}
void GruntLogin::Logon(const char* a2, const char* a3) {
if (this->m_loggedOn) {
return;
}
this->m_reconnect = false;
// TODO
this->m_loginResponse->m_loginState = LOGIN_STATE_CONNECTING;
this->m_loginResponse->m_loginResult = LOGIN_OK;
// TODO
// char v6[64], v7[64];
// SStrCopy(v6, g_LoginStateStringNames[1], sizeof(v6));
// SStrCopy(v7, g_LoginResultStringNames[0], sizeof(v7));
// this->m_loginResponse->Vfunc6(1, 0, 0, v6, v7, 0);
if (!a2) {
a2 = "us.logon.worldofwarcraft.com:3724";
}
this->m_clientLink->Connect(a2);
}

View file

@ -0,0 +1,23 @@
#ifndef NET_LOGIN_GRUNT_LOGIN_HPP
#define NET_LOGIN_GRUNT_LOGIN_HPP
#include "net/grunt/Grunt.hpp"
#include "net/grunt/ClientResponse.hpp"
#include "net/login/Login.hpp"
class GruntLogin : public Login {
public:
// Member variables
Grunt::ClientLink* m_clientLink = nullptr;
// Virtual member functions
virtual ~GruntLogin();
virtual bool Connected(const NETADDR& addr);
virtual void GetLogonMethod();
virtual void GetRealmList();
virtual void Logon(const char* a2, const char* a3);
virtual void Logoff();
virtual void Init(LoginResponse* loginResponse);
};
#endif

29
src/net/login/Login.cpp Normal file
View file

@ -0,0 +1,29 @@
#include "net/login/Login.hpp"
#include <cstring>
#include <storm/Memory.hpp>
#include <storm/String.hpp>
Login::~Login() {
// TODO
}
bool Login::IsReconnect() {
return this->m_reconnect;
}
bool Login::OnlineIdle() {
// TODO
return true;
}
void Login::SetLogonCreds(const char* accountName, const char* password) {
SStrCopy(this->m_accountName, accountName, 1280);
if (this->m_password) {
memset(this->m_password, 0, SStrLen(this->m_password));
SMemFree(this->m_password, __FILE__, __LINE__, 0x0);
}
this->m_password = SStrDupA(password, __FILE__, __LINE__);
}

27
src/net/login/Login.hpp Normal file
View file

@ -0,0 +1,27 @@
#ifndef NET_LOGIN_LOGIN_HPP
#define NET_LOGIN_LOGIN_HPP
#include "net/grunt/ClientResponse.hpp"
class LoginResponse;
class Login : public Grunt::ClientResponse {
public:
// Member variables
bool m_loggedOn = false;
bool m_reconnect = false;
char m_accountName[1280] = {};
char m_rawAccountName[1280] = {};
char* m_password = nullptr;
LoginResponse* m_loginResponse = nullptr;
// Virtual member functions
virtual ~Login();
virtual bool OnlineIdle();
virtual bool IsReconnect();
// Member functions
void SetLogonCreds(const char* accountName, const char* password);
};
#endif

View file

@ -0,0 +1,16 @@
#ifndef NET_LOGIN_LOGIN_RESPONSE_HPP
#define NET_LOGIN_LOGIN_RESPONSE_HPP
#include "net/Types.hpp"
class LoginResponse {
public:
// Member variables
LOGIN_STATE m_loginState;
LOGIN_RESULT m_loginResult;
// Virtual member functions
virtual void LoginServerStatus(LOGIN_STATE state, LOGIN_RESULT result, const char* addrStr, const char* stateStr, const char* resultStr, uint16_t a7) = 0;
};
#endif