mirror of
https://github.com/thunderbrewhq/thunderbrew
synced 2025-04-18 11:02:44 +03:00
feat(net): implement message sending in WowConnection
This commit is contained in:
parent
497520e672
commit
0d30ba07ca
@ -27,10 +27,52 @@
|
|||||||
|
|
||||||
uint64_t WowConnection::s_countTotalBytes;
|
uint64_t WowConnection::s_countTotalBytes;
|
||||||
int32_t WowConnection::s_destroyed;
|
int32_t WowConnection::s_destroyed;
|
||||||
|
int32_t WowConnection::s_lagTestDelayMin;
|
||||||
WowConnectionNet* WowConnection::s_network;
|
WowConnectionNet* WowConnection::s_network;
|
||||||
ATOMIC32 WowConnection::s_numWowConnections;
|
ATOMIC32 WowConnection::s_numWowConnections;
|
||||||
bool (*WowConnection::s_verifyAddr)(const NETADDR*);
|
bool (*WowConnection::s_verifyAddr)(const NETADDR*);
|
||||||
|
|
||||||
|
WowConnection::SENDNODE::SENDNODE(void* data, int32_t size, uint8_t* buf, bool raw) : TSLinkedNode<WowConnection::SENDNODE>() {
|
||||||
|
if (data) {
|
||||||
|
this->data = buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw) {
|
||||||
|
memcpy(this->data, data, size);
|
||||||
|
this->size = size;
|
||||||
|
} else {
|
||||||
|
uint32_t headerSize = size > 0x7FFF ? 3 : 2;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
this->data = &buf[-headerSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto headerBuf = static_cast<uint8_t*>(this->data);
|
||||||
|
|
||||||
|
// Write 2 or 3 byte data size value to header in big endian order
|
||||||
|
if (size > 0x7FFF) {
|
||||||
|
headerBuf[0] = ((size >> (8 * 2)) & 0xff) | 0x80;
|
||||||
|
headerBuf[1] = (size >> (8 * 1)) & 0xff;
|
||||||
|
headerBuf[2] = (size >> (8 * 0)) & 0xff;
|
||||||
|
} else {
|
||||||
|
headerBuf[0] = (size >> (8 * 1)) & 0xff;
|
||||||
|
headerBuf[1] = (size >> (8 * 0)) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
memcpy(static_cast<uint8_t*>(&this->data[headerSize]), data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->size = size + headerSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->datasize = size;
|
||||||
|
this->offset = 0;
|
||||||
|
this->allocsize = 0;
|
||||||
|
|
||||||
|
memcpy(this->header, this->data, std::min(this->size, 8u));
|
||||||
|
}
|
||||||
|
|
||||||
int32_t WowConnection::CreateSocket() {
|
int32_t WowConnection::CreateSocket() {
|
||||||
int32_t sock = socket(AF_INET, SOCK_STREAM, 0);
|
int32_t sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
|
||||||
@ -556,6 +598,11 @@ void WowConnection::DoWrites() {
|
|||||||
this->Release();
|
this->Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WowConnection::FreeSendNode(SENDNODE* sn) {
|
||||||
|
// TODO WDataStore::FreeBuffer(sn, sn->datasize + sizeof(SENDNODE) + 3);
|
||||||
|
SMemFree(sn, __FILE__, __LINE__, 0x0);
|
||||||
|
}
|
||||||
|
|
||||||
WOW_CONN_STATE WowConnection::GetState() {
|
WOW_CONN_STATE WowConnection::GetState() {
|
||||||
return this->m_connState;
|
return this->m_connState;
|
||||||
}
|
}
|
||||||
@ -568,6 +615,12 @@ void WowConnection::Init(WowConnectionResponse* response, void (*func)(void)) {
|
|||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
|
this->m_sendDepth = 0;
|
||||||
|
this->m_sendDepthBytes = 0;
|
||||||
|
this->m_maxSendDepth = 100000;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
|
||||||
this->m_connState = WOWC_UNINITIALIZED;
|
this->m_connState = WOWC_UNINITIALIZED;
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
@ -591,6 +644,7 @@ void WowConnection::Init(WowConnectionResponse* response, void (*func)(void)) {
|
|||||||
this->m_readBufferSize = 0;
|
this->m_readBufferSize = 0;
|
||||||
|
|
||||||
this->m_event = nullptr;
|
this->m_event = nullptr;
|
||||||
|
this->m_encrypt = false;
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
@ -598,6 +652,25 @@ void WowConnection::Init(WowConnectionResponse* response, void (*func)(void)) {
|
|||||||
this->m_type = WOWC_TYPE_MESSAGES;
|
this->m_type = WOWC_TYPE_MESSAGES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WowConnection::SENDNODE* WowConnection::NewSendNode(void* data, int32_t size, bool raw) {
|
||||||
|
// TODO counters
|
||||||
|
|
||||||
|
// SENDNODEs are prefixed to their buffers, with an extra 3 bytes reserved for size-prefixing
|
||||||
|
uint32_t allocsize = size + sizeof(SENDNODE) + 3;
|
||||||
|
|
||||||
|
// TODO WDataStore::AllocBuffer(allocsize);
|
||||||
|
|
||||||
|
auto m = SMemAlloc(allocsize, __FILE__, __LINE__, 0x0);
|
||||||
|
auto buf = &static_cast<uint8_t*>(m)[sizeof(SENDNODE)];
|
||||||
|
auto sn = new (m) SENDNODE(data, size, buf, raw);
|
||||||
|
|
||||||
|
sn->allocsize = allocsize;
|
||||||
|
|
||||||
|
// TODO latency tracking
|
||||||
|
|
||||||
|
return sn;
|
||||||
|
}
|
||||||
|
|
||||||
void WowConnection::Release() {
|
void WowConnection::Release() {
|
||||||
if (SInterlockedDecrement(&this->m_refCount) <= 0) {
|
if (SInterlockedDecrement(&this->m_refCount) <= 0) {
|
||||||
if (WowConnection::s_network) {
|
if (WowConnection::s_network) {
|
||||||
@ -626,6 +699,94 @@ void WowConnection::ReleaseResponseRef() {
|
|||||||
this->m_responseLock.Leave();
|
this->m_responseLock.Leave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WC_SEND_RESULT WowConnection::Send(CDataStore* msg, int32_t a3) {
|
||||||
|
uint8_t* data;
|
||||||
|
msg->GetDataInSitu(reinterpret_cast<void*&>(data), msg->Size());
|
||||||
|
|
||||||
|
WowConnection::s_countTotalBytes += msg->Size();
|
||||||
|
|
||||||
|
this->m_lock.Enter();
|
||||||
|
|
||||||
|
if (msg->Size() == 0 || this->m_connState != WOWC_CONNECTED) {
|
||||||
|
this->m_lock.Leave();
|
||||||
|
return WC_SEND_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Queue send
|
||||||
|
|
||||||
|
if (WowConnection::s_lagTestDelayMin || this->m_sendList.Head()) {
|
||||||
|
auto sn = this->NewSendNode(data, msg->Size(), false);
|
||||||
|
|
||||||
|
if (this->m_encrypt) {
|
||||||
|
// TODO encryption
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_sendList.LinkToTail(sn);
|
||||||
|
|
||||||
|
this->m_sendDepth++;
|
||||||
|
this->m_sendDepthBytes += sn->size;
|
||||||
|
|
||||||
|
WowConnection::s_network->PlatformChangeState(this, this->m_connState);
|
||||||
|
|
||||||
|
if (this->m_sendDepth < this->m_maxSendDepth) {
|
||||||
|
this->m_lock.Leave();
|
||||||
|
return WC_SEND_QUEUED;
|
||||||
|
} else {
|
||||||
|
// TODO handle max queue send depth reached
|
||||||
|
|
||||||
|
this->m_lock.Leave();
|
||||||
|
return WC_SEND_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send immediately
|
||||||
|
|
||||||
|
SENDNODE* sn;
|
||||||
|
bool snOnStack;
|
||||||
|
|
||||||
|
if (msg->Size() > 100000) {
|
||||||
|
snOnStack = false;
|
||||||
|
sn = this->NewSendNode(data, msg->Size(), false);
|
||||||
|
} else if (a3 < 3) {
|
||||||
|
snOnStack = true;
|
||||||
|
|
||||||
|
auto m = alloca(msg->Size() + sizeof(SENDNODE) + 3);
|
||||||
|
auto buf = &static_cast<uint8_t*>(m)[sizeof(SENDNODE)];
|
||||||
|
sn = new (m) SENDNODE(data, msg->Size(), buf, false);
|
||||||
|
} else {
|
||||||
|
snOnStack = true;
|
||||||
|
|
||||||
|
auto m = alloca(msg->Size() + sizeof(SENDNODE));
|
||||||
|
auto buf = &static_cast<uint8_t*>(m)[sizeof(SENDNODE)];
|
||||||
|
sn = new (m) SENDNODE(nullptr, msg->Size(), buf, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->m_encrypt) {
|
||||||
|
// TODO encryption
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t written;
|
||||||
|
#if defined(WHOA_SYSTEM_WIN)
|
||||||
|
written = send(this->m_sock, sn->data, sn->size, 0x0);
|
||||||
|
#elif defined(WHOA_SYSTEM_MAC)
|
||||||
|
written = write(this->m_sock, sn->data, sn->size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (written == sn->size) {
|
||||||
|
if (!snOnStack) {
|
||||||
|
this->FreeSendNode(sn);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_lock.Leave();
|
||||||
|
return WC_SEND_SENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO split writes, errors, etc
|
||||||
|
STORM_ASSERT(false);
|
||||||
|
|
||||||
|
return WC_SEND_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
WC_SEND_RESULT WowConnection::SendRaw(uint8_t* data, int32_t len, bool a4) {
|
WC_SEND_RESULT WowConnection::SendRaw(uint8_t* data, int32_t len, bool a4) {
|
||||||
WowConnection::s_countTotalBytes += len;
|
WowConnection::s_countTotalBytes += len;
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class CDataStore;
|
||||||
class WowConnectionNet;
|
class WowConnectionNet;
|
||||||
class WowConnectionResponse;
|
class WowConnectionResponse;
|
||||||
|
|
||||||
@ -26,11 +27,17 @@ class WowConnection {
|
|||||||
uint32_t size;
|
uint32_t size;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
uint32_t datasize;
|
uint32_t datasize;
|
||||||
|
uint8_t header[8];
|
||||||
|
uint32_t uint20;
|
||||||
|
uint32_t allocsize;
|
||||||
|
|
||||||
|
SENDNODE(void* data, int32_t size, uint8_t* buf, bool raw);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Static variables
|
// Static variables
|
||||||
static uint64_t s_countTotalBytes;
|
static uint64_t s_countTotalBytes;
|
||||||
static int32_t s_destroyed;
|
static int32_t s_destroyed;
|
||||||
|
static int32_t s_lagTestDelayMin;
|
||||||
static WowConnectionNet* s_network;
|
static WowConnectionNet* s_network;
|
||||||
static ATOMIC32 s_numWowConnections;
|
static ATOMIC32 s_numWowConnections;
|
||||||
static bool (*s_verifyAddr)(const NETADDR*);
|
static bool (*s_verifyAddr)(const NETADDR*);
|
||||||
@ -54,12 +61,16 @@ class WowConnection {
|
|||||||
int32_t m_responseRef;
|
int32_t m_responseRef;
|
||||||
uintptr_t m_responseRefThread;
|
uintptr_t m_responseRefThread;
|
||||||
STORM_LIST(SENDNODE) m_sendList;
|
STORM_LIST(SENDNODE) m_sendList;
|
||||||
|
int32_t m_sendDepth;
|
||||||
|
uint32_t m_sendDepthBytes;
|
||||||
|
int32_t m_maxSendDepth;
|
||||||
uint32_t m_serviceFlags;
|
uint32_t m_serviceFlags;
|
||||||
TSLink<WowConnection> m_netlink;
|
TSLink<WowConnection> m_netlink;
|
||||||
SCritSect m_lock;
|
SCritSect m_lock;
|
||||||
ATOMIC32 m_serviceCount;
|
ATOMIC32 m_serviceCount;
|
||||||
void* m_event;
|
void* m_event;
|
||||||
WOWC_TYPE m_type;
|
WOWC_TYPE m_type;
|
||||||
|
bool m_encrypt;
|
||||||
|
|
||||||
// Member functions
|
// Member functions
|
||||||
WowConnection(WowConnectionResponse* response, void (*func)(void));
|
WowConnection(WowConnectionResponse* response, void (*func)(void));
|
||||||
@ -78,10 +89,13 @@ class WowConnection {
|
|||||||
void DoReads();
|
void DoReads();
|
||||||
void DoStreamReads();
|
void DoStreamReads();
|
||||||
void DoWrites();
|
void DoWrites();
|
||||||
|
void FreeSendNode(SENDNODE* sn);
|
||||||
WOW_CONN_STATE GetState();
|
WOW_CONN_STATE GetState();
|
||||||
void Init(WowConnectionResponse* response, void (*func)(void));
|
void Init(WowConnectionResponse* response, void (*func)(void));
|
||||||
|
SENDNODE* NewSendNode(void* data, int32_t size, bool raw);
|
||||||
void Release();
|
void Release();
|
||||||
void ReleaseResponseRef();
|
void ReleaseResponseRef();
|
||||||
|
WC_SEND_RESULT Send(CDataStore* msg, int32_t a3);
|
||||||
WC_SEND_RESULT SendRaw(uint8_t* data, int32_t len, bool a4);
|
WC_SEND_RESULT SendRaw(uint8_t* data, int32_t len, bool a4);
|
||||||
void SetEncryptionType(WC_ENCRYPT_TYPE encryptType);
|
void SetEncryptionType(WC_ENCRYPT_TYPE encryptType);
|
||||||
void SetState(WOW_CONN_STATE state);
|
void SetState(WOW_CONN_STATE state);
|
||||||
|
Loading…
Reference in New Issue
Block a user