whoa/src/net/connection/bsd/WowConnectionNet.cpp

188 lines
5.1 KiB
C++

#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::PlatformRemove(WowConnection* connection) {
char buf = '\1';
write(s_workerPipe[1], &buf, sizeof(buf));
}
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_ZERO(&readFds);
fd_set writeFds;
FD_ZERO(&writeFds);
fd_set errorFds;
FD_ZERO(&errorFds);
FD_SET(s_workerPipe[0], &readFds);
auto fdCount = s_workerPipe[0];
this->m_connectionsLock.Enter();
uint32_t connectionCount = 0;
uint32_t disconnectionCount = 0;
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: {
FD_SET(connection->m_sock, &writeFds);
FD_SET(connection->m_sock, &errorFds);
connections.GrowToFit(connectionCount, 0);
connections[connectionCount] = connection;
connection->AddRef();
fdCount = std::max(fdCount, connection->m_sock);
break;
}
case WOWC_LISTENING: {
FD_SET(connection->m_sock, &readFds);
connections.GrowToFit(connectionCount, 0);
connections[connectionCount] = connection;
connection->AddRef();
fdCount = std::max(fdCount, connection->m_sock);
break;
}
case WOWC_CONNECTED: {
FD_SET(connection->m_sock, &readFds);
FD_SET(connection->m_sock, &errorFds);
// TODO
connections.GrowToFit(connectionCount, 0);
connections[connectionCount] = connection;
connection->AddRef();
fdCount = std::max(fdCount, connection->m_sock);
break;
}
case WOWC_DISCONNECTING: {
// TODO
disconnectionCount++;
connections.GrowToFit(connectionCount, 0);
connections[connectionCount] = connection;
connection->AddRef();
break;
}
default: {
break;
}
}
connectionCount++;
}
this->m_connectionsLock.Leave();
if (disconnectionCount > 0) {
timeout = { 0, 0 };
}
if (connectionCount > 0) {
// TODO
}
select(fdCount + 1, &readFds, &writeFds, &errorFds, &timeout);
auto v1 = s_workerPipe[0];
if (FD_ISSET(s_workerPipe[0], &readFds)) {
while (read(v1, buf, 1u) > 0) {
v1 = s_workerPipe[0];
}
}
for (int32_t i = 0; i < connectionCount; 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));
}