mirror of
https://github.com/thunderbrewhq/thunderbrew
synced 2025-04-16 01:55:21 +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;
|
||||
int32_t WowConnection::s_destroyed;
|
||||
int32_t WowConnection::s_lagTestDelayMin;
|
||||
WowConnectionNet* WowConnection::s_network;
|
||||
ATOMIC32 WowConnection::s_numWowConnections;
|
||||
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 sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
@ -556,6 +598,11 @@ void WowConnection::DoWrites() {
|
||||
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() {
|
||||
return this->m_connState;
|
||||
}
|
||||
@ -568,6 +615,12 @@ void WowConnection::Init(WowConnectionResponse* response, void (*func)(void)) {
|
||||
|
||||
// TODO
|
||||
|
||||
this->m_sendDepth = 0;
|
||||
this->m_sendDepthBytes = 0;
|
||||
this->m_maxSendDepth = 100000;
|
||||
|
||||
// TODO
|
||||
|
||||
this->m_connState = WOWC_UNINITIALIZED;
|
||||
|
||||
// TODO
|
||||
@ -591,6 +644,7 @@ void WowConnection::Init(WowConnectionResponse* response, void (*func)(void)) {
|
||||
this->m_readBufferSize = 0;
|
||||
|
||||
this->m_event = nullptr;
|
||||
this->m_encrypt = false;
|
||||
|
||||
// TODO
|
||||
|
||||
@ -598,6 +652,25 @@ void WowConnection::Init(WowConnectionResponse* response, void (*func)(void)) {
|
||||
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() {
|
||||
if (SInterlockedDecrement(&this->m_refCount) <= 0) {
|
||||
if (WowConnection::s_network) {
|
||||
@ -626,6 +699,94 @@ void WowConnection::ReleaseResponseRef() {
|
||||
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) {
|
||||
WowConnection::s_countTotalBytes += len;
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
class CDataStore;
|
||||
class WowConnectionNet;
|
||||
class WowConnectionResponse;
|
||||
|
||||
@ -26,11 +27,17 @@ class WowConnection {
|
||||
uint32_t size;
|
||||
uint32_t offset;
|
||||
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 uint64_t s_countTotalBytes;
|
||||
static int32_t s_destroyed;
|
||||
static int32_t s_lagTestDelayMin;
|
||||
static WowConnectionNet* s_network;
|
||||
static ATOMIC32 s_numWowConnections;
|
||||
static bool (*s_verifyAddr)(const NETADDR*);
|
||||
@ -54,12 +61,16 @@ class WowConnection {
|
||||
int32_t m_responseRef;
|
||||
uintptr_t m_responseRefThread;
|
||||
STORM_LIST(SENDNODE) m_sendList;
|
||||
int32_t m_sendDepth;
|
||||
uint32_t m_sendDepthBytes;
|
||||
int32_t m_maxSendDepth;
|
||||
uint32_t m_serviceFlags;
|
||||
TSLink<WowConnection> m_netlink;
|
||||
SCritSect m_lock;
|
||||
ATOMIC32 m_serviceCount;
|
||||
void* m_event;
|
||||
WOWC_TYPE m_type;
|
||||
bool m_encrypt;
|
||||
|
||||
// Member functions
|
||||
WowConnection(WowConnectionResponse* response, void (*func)(void));
|
||||
@ -78,10 +89,13 @@ class WowConnection {
|
||||
void DoReads();
|
||||
void DoStreamReads();
|
||||
void DoWrites();
|
||||
void FreeSendNode(SENDNODE* sn);
|
||||
WOW_CONN_STATE GetState();
|
||||
void Init(WowConnectionResponse* response, void (*func)(void));
|
||||
SENDNODE* NewSendNode(void* data, int32_t size, bool raw);
|
||||
void Release();
|
||||
void ReleaseResponseRef();
|
||||
WC_SEND_RESULT Send(CDataStore* msg, int32_t a3);
|
||||
WC_SEND_RESULT SendRaw(uint8_t* data, int32_t len, bool a4);
|
||||
void SetEncryptionType(WC_ENCRYPT_TYPE encryptType);
|
||||
void SetState(WOW_CONN_STATE state);
|
||||
|
Loading…
Reference in New Issue
Block a user