From 497520e6725acb53238a979ca5f28ecf644d456a Mon Sep 17 00:00:00 2001 From: fallenoak Date: Tue, 21 Mar 2023 16:39:15 -0500 Subject: [PATCH] feat(net): finish basic networking support for windows --- src/net/connection/WowConnection.cpp | 32 +++- src/net/connection/WowConnection.hpp | 1 + src/net/connection/WowConnectionNet.hpp | 1 + .../connection/winsock/WowConnectionNet.cpp | 138 +++++++++++++++++- 4 files changed, 163 insertions(+), 9 deletions(-) diff --git a/src/net/connection/WowConnection.cpp b/src/net/connection/WowConnection.cpp index a329be0..4b785f9 100644 --- a/src/net/connection/WowConnection.cpp +++ b/src/net/connection/WowConnection.cpp @@ -590,6 +590,8 @@ void WowConnection::Init(WowConnectionResponse* response, void (*func)(void)) { this->m_readBytes = 0; this->m_readBufferSize = 0; + this->m_event = nullptr; + // TODO this->SetState(WOWC_INITIALIZED); @@ -635,7 +637,20 @@ WC_SEND_RESULT WowConnection::SendRaw(uint8_t* data, int32_t len, bool a4) { STORM_ASSERT(this->m_sock >= 0); #if defined (WHOA_SYSTEM_WIN) - // TODO + if (this->m_sendList.Head()) { + // TODO + } else { + auto written = send(this->m_sock, reinterpret_cast(data), len, 0x0); + + if (written == len) { + this->m_lock.Leave(); + return WC_SEND_SENT; + } + + if (written < 0) { + // TODO + } + } #elif defined(WHOA_SYSTEM_MAC) || defined(WHOA_SYSTEM_LINUX) if (this->m_sendList.Head()) { // TODO @@ -697,11 +712,15 @@ void WowConnection::StartConnect() { return; } -#if defined(WHOA_SYSTEM_MAC) +#if defined(WHOA_SYSTEM_WIN) + u_long argp = 1; + ioctlsocket(this->m_sock, FIONBIO, &argp); +#elif 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)); +#endif sockaddr_in addr; addr.sin_family = AF_INET; @@ -720,11 +739,19 @@ void WowConnection::StartConnect() { return; } +#if defined(WHOA_SYSTEM_WIN) + if (WSAGetLastError() == WSAEWOULDBLOCK) { + this->m_lock.Leave(); + + return; + } +#elif defined(WHOA_SYSTEM_MAC) if (errno == EAGAIN || errno == EINTR || errno == EINPROGRESS) { this->m_lock.Leave(); return; } +#endif WowConnection::s_network->Remove(this); this->CloseSocket(this->m_sock); @@ -733,5 +760,4 @@ void WowConnection::StartConnect() { this->SetState(WOWC_ERROR); this->m_lock.Leave(); -#endif } diff --git a/src/net/connection/WowConnection.hpp b/src/net/connection/WowConnection.hpp index 0181054..7b064ae 100644 --- a/src/net/connection/WowConnection.hpp +++ b/src/net/connection/WowConnection.hpp @@ -58,6 +58,7 @@ class WowConnection { TSLink m_netlink; SCritSect m_lock; ATOMIC32 m_serviceCount; + void* m_event; WOWC_TYPE m_type; // Member functions diff --git a/src/net/connection/WowConnectionNet.hpp b/src/net/connection/WowConnectionNet.hpp index 00fd6b1..7cd8f8b 100644 --- a/src/net/connection/WowConnectionNet.hpp +++ b/src/net/connection/WowConnectionNet.hpp @@ -29,6 +29,7 @@ class WowConnectionNet { STORM_EXPLICIT_LIST(WowConnection, m_netlink) m_connections; SSemaphore m_workerSem; void (*m_threadinit)(); + void* event8E8; // Member functions WowConnectionNet(uint32_t numThreads, void (*threadinit)()) diff --git a/src/net/connection/winsock/WowConnectionNet.cpp b/src/net/connection/winsock/WowConnectionNet.cpp index 988b57e..2737d3e 100644 --- a/src/net/connection/winsock/WowConnectionNet.cpp +++ b/src/net/connection/winsock/WowConnectionNet.cpp @@ -1,25 +1,151 @@ #include "net/connection/WowConnectionNet.hpp" +#include +#include void WowConnectionNet::PlatformAdd(WowConnection* connection) { - // TODO + if (!connection->m_event) { + connection->m_event = WSACreateEvent(); + } + + uint32_t on = 1; + setsockopt(connection->m_sock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&on), sizeof(on)); + + SetEvent(this->event8E8); } void WowConnectionNet::PlatformChangeState(WowConnection* connection, WOW_CONN_STATE state) { - // TODO + uint32_t networkEvents = 0x0; + + switch (connection->GetState()) { + case WOWC_CONNECTING: { + networkEvents = FD_CLOSE | FD_CONNECT | FD_WRITE; + } + + case WOWC_LISTENING: { + networkEvents = FD_ACCEPT; + } + + case WOWC_CONNECTED: { + // TODO conditional network event + networkEvents = FD_CLOSE | FD_READ; + } + } + + if (connection->m_event && connection->m_sock >= 0) { + WSAEventSelect(connection->m_sock, connection->m_event, networkEvents); + } + + SetEvent(this->event8E8); } void WowConnectionNet::PlatformInit(bool useEngine) { - // TODO + WSADATA wsaData; + auto err = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (err || wsaData.wVersion != MAKEWORD(2, 2)) { + return; + } + + this->event8E8 = CreateEvent(nullptr, true, false, nullptr); } void WowConnectionNet::PlatformRemove(WowConnection* connection) { - // TODO + SetEvent(this->event8E8); } void WowConnectionNet::PlatformRun() { - // TODO + uint32_t timeout = 500; + + WowConnection* connections[64]; + HANDLE connectionEvents[64]; + + while (!this->m_stop) { + this->m_connectionsLock.Enter(); + + uint32_t connectionCount = 0; + + connections[connectionCount] = nullptr; + connectionEvents[connectionCount] = this->event8E8; + connectionCount++; + + for (auto connection = this->m_connections.Head(); connection; connection = this->m_connections.Next(connection)) { + if (connection->m_serviceCount) { + continue; + } + + switch (connection->GetState()) { + case WOWC_CONNECTING: { + WSAEventSelect(connection->m_sock, connection->m_event, FD_CONNECT | FD_CLOSE); + break; + } + + case WOWC_LISTENING: { + WSAEventSelect(connection->m_sock, connection->m_event, FD_ACCEPT); + break; + } + + case WOWC_CONNECTED: { + // TODO conditional network event + WSAEventSelect(connection->m_sock, connection->m_event, FD_CONNECT | FD_READ); + break; + } + + case WOWC_DISCONNECTED: { + timeout = 0; + break; + } + + default: { + break; + } + } + + if (connectionCount < 64) { + connection->AddRef(); + + connections[connectionCount] = connection; + connectionEvents[connectionCount] = connection->m_event; + connectionCount++; + + // TODO + } + } + + this->m_connectionsLock.Leave(); + + auto waitIndex = WaitForMultipleObjects(connectionCount, connectionEvents, false, timeout); + + if (waitIndex == 0) { + ResetEvent(connectionEvents[0]); + } else { + for (uint32_t i = 1; i < connectionCount; i++) { + WSANETWORKEVENTS networkEvents; + WSAEnumNetworkEvents(connections[i]->m_sock, connectionEvents[i], &networkEvents); + + uint32_t signalFlags = 0x0; + if (networkEvents.lNetworkEvents & (FD_CLOSE | FD_ACCEPT | FD_READ)) { + signalFlags |= 0x2; + } + if (networkEvents.lNetworkEvents & (FD_CLOSE | FD_CONNECT | FD_WRITE)) { + signalFlags |= 0x1; + } + if (connections[i]->m_connState == WOWC_DISCONNECTING) { + signalFlags |= 0x8; + } + + // TODO timeout manipulation + + if (signalFlags) { + this->SignalWorker(connections[i], signalFlags); + } + } + } + + for (uint32_t i = 1; i < connectionCount; i++) { + connections[i]->Release(); + } + } } void WowConnectionNet::PlatformWorkerReady() { - // TODO + SetEvent(this->event8E8); }