update lcemp networking

This commit is contained in:
2026-08-14 07:02:50 +03:00
parent 125819419f
commit 6853eab85f
51 changed files with 629 additions and 183 deletions
@@ -39,7 +39,7 @@ BYTE NetworkSocketLayer::s_nextSmallId = 1;
CRITICAL_SECTION NetworkSocketLayer::s_sendLock;
CRITICAL_SECTION NetworkSocketLayer::s_connectionsLock;
std::vector<RemoteConnection> NetworkSocketLayer::s_connections;
RemoteConnection NetworkSocketLayer::s_connections[NETWORK_LAN_MAX_CLIENTS + 1];
C4JThread* NetworkSocketLayer::s_advertiseThread = NULL;
volatile bool NetworkSocketLayer::s_advertising = false;
@@ -55,6 +55,9 @@ std::vector<LANSession> NetworkSocketLayer::s_discoveredSessions;
CRITICAL_SECTION NetworkSocketLayer::s_disconnectLock;
std::vector<BYTE> NetworkSocketLayer::s_disconnectedSmallIds;
CRITICAL_SECTION NetworkSocketLayer::s_pendingJoinLock;
std::vector<BYTE> NetworkSocketLayer::s_pendingJoinSmallIds;
CRITICAL_SECTION NetworkSocketLayer::s_freeSmallIdLock;
std::vector<BYTE> NetworkSocketLayer::s_freeSmallIds;
@@ -83,7 +86,17 @@ bool NetworkSocketLayer::Initialize()
InitializeCriticalSection(&s_advertiseLock);
InitializeCriticalSection(&s_discoveryLock);
InitializeCriticalSection(&s_disconnectLock);
InitializeCriticalSection(&s_pendingJoinLock);
InitializeCriticalSection(&s_freeSmallIdLock);
for (int i = 0; i < NETWORK_LAN_MAX_CLIENTS + 1; i++)
{
s_connections[i].tcpSocket = INVALID_SOCKET;
s_connections[i].smallId = 0;
s_connections[i].recvThread = NULL;
s_connections[i].active = false;
InitializeCriticalSection(&s_connections[i].sendLock);
}
s_locksCreated = true;
}
@@ -167,7 +180,7 @@ void NetworkSocketLayer::Shutdown()
EnterCriticalSection(&s_connectionsLock);
for (size_t i = 0; i < s_connections.size(); i++)
for (int i = 0; i < NETWORK_LAN_MAX_CLIENTS + 1; i++)
{
s_connections[i].active = false;
#if defined _WINDOWS64 || defined _XBOX
@@ -177,9 +190,16 @@ void NetworkSocketLayer::Shutdown()
#endif
{
closesocket(s_connections[i].tcpSocket);
s_connections[i].tcpSocket = INVALID_SOCKET;
}
if (s_connections[i].recvThread != NULL)
{
s_connections[i].recvThread->WaitForCompletion(2000);
delete s_connections[i].recvThread;
s_connections[i].recvThread = NULL;
}
DeleteCriticalSection(&s_connections[i].sendLock);
}
s_connections.clear();
LeaveCriticalSection(&s_connectionsLock);
if (s_acceptThread != NULL)
@@ -204,6 +224,8 @@ void NetworkSocketLayer::Shutdown()
DeleteCriticalSection(&s_discoveryLock);
DeleteCriticalSection(&s_disconnectLock);
s_disconnectedSmallIds.clear();
DeleteCriticalSection(&s_pendingJoinLock);
s_pendingJoinSmallIds.clear();
DeleteCriticalSection(&s_freeSmallIdLock);
s_freeSmallIds.clear();
s_locksCreated = false;
@@ -219,6 +241,14 @@ bool NetworkSocketLayer::HostGame(int port)
s_isHost = true;
s_localSmallId = 0;
s_hostSmallId = 0;
s_connected = false;
s_active = false;
if (s_hostConnectionSocket != INVALID_SOCKET)
{
closesocket(s_hostConnectionSocket);
s_hostConnectionSocket = INVALID_SOCKET;
}
s_nextSmallId = 1;
s_hostGamePort = port;
@@ -786,9 +816,9 @@ bool NetworkSocketLayer::JoinGame(const char *ip, int port)
bool NetworkSocketLayer::SendOnSocket(SOCKET sock, const void *data, int dataSize)
{
#if defined _WINDOWS64 || defined _XBOX
if (sock == INVALID_SOCKET || dataSize <= 0) return false;
if (sock == INVALID_SOCKET || dataSize <= 0 || dataSize > NETWORK_LAN_MAX_PACKET_SIZE) return false;
#elif defined __PS3__ || defined __ORBIS__ || defined __PSVITA__
if (sock < 0 || dataSize <= 0) return false;
if (sock < 0 || dataSize <= 0 || dataSize > NETWORK_LAN_MAX_PACKET_SIZE) return false;
#endif
EnterCriticalSection(&s_sendLock);
@@ -809,10 +839,7 @@ bool NetworkSocketLayer::SendOnSocket(SOCKET sock, const void *data, int dataSiz
#elif defined __PS3__ || defined __ORBIS__ || defined __PSVITA__
if (sent < 0 || sent == 0)
#endif
{
LeaveCriticalSection(&s_sendLock);
return false;
}
totalSent += sent;
}
@@ -826,14 +853,10 @@ bool NetworkSocketLayer::SendOnSocket(SOCKET sock, const void *data, int dataSiz
#elif defined __PS3__ || defined __ORBIS__ || defined __PSVITA__
if (sent < 0 || sent == 0)
#endif
{
LeaveCriticalSection(&s_sendLock);
return false;
}
totalSent += sent;
}
LeaveCriticalSection(&s_sendLock);
return true;
}
@@ -843,31 +866,38 @@ bool NetworkSocketLayer::SendToSmallId(BYTE targetSmallId, const void *data, int
if (s_isHost)
{
SOCKET sock = GetSocketForSmallId(targetSmallId);
#if defined _WINDOWS64 || defined _XBOX
if (sock == INVALID_SOCKET) return false;
#elif defined __PS3__ || defined __ORBIS__ || defined __PSVITA__
if (sock < 0) return false;
#endif
return SendOnSocket(sock, data, dataSize);
EnterCriticalSection(&s_connectionsLock);
if (targetSmallId >= NETWORK_LAN_MAX_CLIENTS + 1 || !s_connections[targetSmallId].active)
{
LeaveCriticalSection(&s_connectionsLock);
return false;
}
SOCKET sock = s_connections[targetSmallId].tcpSocket;
CRITICAL_SECTION *pLock = &s_connections[targetSmallId].sendLock;
LeaveCriticalSection(&s_connectionsLock);
EnterCriticalSection(pLock);
bool result = SendOnSocket(sock, data, dataSize);
LeaveCriticalSection(pLock);
return result;
}
else
{
return SendOnSocket(s_hostConnectionSocket, data, dataSize);
EnterCriticalSection(&s_sendLock);
bool result = SendOnSocket(s_hostConnectionSocket, data, dataSize);
LeaveCriticalSection(&s_sendLock);
return result;
}
}
SOCKET NetworkSocketLayer::GetSocketForSmallId(BYTE smallId)
{
EnterCriticalSection(&s_connectionsLock);
for (size_t i = 0; i < s_connections.size(); i++)
if (smallId < NETWORK_LAN_MAX_CLIENTS + 1 && s_connections[smallId].active)
{
if (s_connections[i].smallId == smallId && s_connections[i].active)
{
SOCKET sock = s_connections[i].tcpSocket;
LeaveCriticalSection(&s_connectionsLock);
return sock;
}
SOCKET sock = s_connections[smallId].tcpSocket;
LeaveCriticalSection(&s_connectionsLock);
return sock;
}
LeaveCriticalSection(&s_connectionsLock);
#if defined _WINDOWS64 || defined _XBOX
@@ -981,15 +1011,19 @@ int NetworkSocketLayer::AcceptThreadProc(LPVOID param)
continue;
}
RemoteConnection conn;
RemoteConnection &conn = s_connections[assignedSmallId];
EnterCriticalSection(&s_connectionsLock);
if (conn.recvThread != NULL)
{
conn.recvThread->WaitForCompletion(2000);
delete conn.recvThread;
conn.recvThread = NULL;
}
conn.tcpSocket = clientSocket;
conn.smallId = assignedSmallId;
conn.active = true;
conn.recvThread = NULL;
EnterCriticalSection(&s_connectionsLock);
s_connections.push_back(conn);
int connIdx = (int)s_connections.size() - 1;
LeaveCriticalSection(&s_connectionsLock);
app.DebugPrintf("Win64 LAN: Client connected, assigned smallId=%d\n", assignedSmallId);
@@ -999,17 +1033,17 @@ int NetworkSocketLayer::AcceptThreadProc(LPVOID param)
extern void Win64_SetupRemoteQNetPlayer(IQNetPlayer *player, BYTE smallId, bool isHost, bool isLocal);
Win64_SetupRemoteQNetPlayer(qnetPlayer, assignedSmallId, false, false);
extern CPlatformNetworkManagerStub *g_pPlatformNetworkManager;
g_pPlatformNetworkManager->NotifyPlayerJoined(qnetPlayer);
EnterCriticalSection(&s_pendingJoinLock);
s_pendingJoinSmallIds.push_back(assignedSmallId);
LeaveCriticalSection(&s_pendingJoinLock);
DWORD *threadParam = new DWORD;
*threadParam = connIdx;
*threadParam = assignedSmallId;
C4JThread* hThread = new C4JThread(RecvThreadProc, threadParam, "RecvThreadProc");
hThread->Run();
EnterCriticalSection(&s_connectionsLock);
if (connIdx < (int)s_connections.size())
s_connections[connIdx].recvThread = hThread;
s_connections[assignedSmallId].recvThread = hThread;
LeaveCriticalSection(&s_connectionsLock);
}
return 0;
@@ -1017,17 +1051,16 @@ int NetworkSocketLayer::AcceptThreadProc(LPVOID param)
int NetworkSocketLayer::RecvThreadProc(LPVOID param)
{
DWORD connIdx = *(DWORD *)param;
BYTE clientSmallId = (BYTE)*(DWORD *)param;
delete (DWORD *)param;
EnterCriticalSection(&s_connectionsLock);
if (connIdx >= (DWORD)s_connections.size())
if (clientSmallId >= NETWORK_LAN_MAX_CLIENTS + 1 || !s_connections[clientSmallId].active)
{
LeaveCriticalSection(&s_connectionsLock);
return 0;
}
SOCKET sock = s_connections[connIdx].tcpSocket;
BYTE clientSmallId = s_connections[connIdx].smallId;
SOCKET sock = s_connections[clientSmallId].tcpSocket;
LeaveCriticalSection(&s_connectionsLock);
std::vector<BYTE> recvBuf;
@@ -1048,7 +1081,7 @@ int NetworkSocketLayer::RecvThreadProc(LPVOID param)
((uint32_t)header[2] << 8) |
((uint32_t)header[3]);
if (packetSize <= 0 || packetSize > NETWORK_LAN_MAX_PACKET_SIZE)
if (packetSize <= 0 || (unsigned int)packetSize > NETWORK_LAN_MAX_PACKET_SIZE)
{
app.DebugPrintf("LAN: Invalid packet size %d from client smallId=%d (max=%d)\n",
packetSize,
@@ -1073,18 +1106,11 @@ int NetworkSocketLayer::RecvThreadProc(LPVOID param)
}
EnterCriticalSection(&s_connectionsLock);
for (size_t i = 0; i < s_connections.size(); i++)
s_connections[clientSmallId].active = false;
if (s_connections[clientSmallId].tcpSocket != INVALID_SOCKET)
{
if (s_connections[i].smallId == clientSmallId)
{
s_connections[i].active = false;
if (s_connections[i].tcpSocket != INVALID_SOCKET)
{
closesocket(s_connections[i].tcpSocket);
s_connections[i].tcpSocket = INVALID_SOCKET;
}
break;
}
closesocket(s_connections[clientSmallId].tcpSocket);
s_connections[clientSmallId].tcpSocket = INVALID_SOCKET;
}
LeaveCriticalSection(&s_connectionsLock);
@@ -1116,18 +1142,34 @@ void NetworkSocketLayer::PushFreeSmallId(BYTE smallId)
LeaveCriticalSection(&s_freeSmallIdLock);
}
bool NetworkSocketLayer::PopPendingJoinSmallId(BYTE *outSmallId)
{
bool found = false;
EnterCriticalSection(&s_pendingJoinLock);
if (!s_pendingJoinSmallIds.empty())
{
*outSmallId = s_pendingJoinSmallIds.back();
s_pendingJoinSmallIds.pop_back();
found = true;
}
LeaveCriticalSection(&s_pendingJoinLock);
return found;
}
bool NetworkSocketLayer::IsSmallIdConnected(BYTE smallId)
{
if (smallId >= NETWORK_LAN_MAX_CLIENTS + 1) return false;
return s_connections[smallId].active;
}
void NetworkSocketLayer::CloseConnectionBySmallId(BYTE smallId)
{
EnterCriticalSection(&s_connectionsLock);
for (size_t i = 0; i < s_connections.size(); i++)
if (smallId < NETWORK_LAN_MAX_CLIENTS + 1 && s_connections[smallId].active && s_connections[smallId].tcpSocket != INVALID_SOCKET)
{
if (s_connections[i].smallId == smallId && s_connections[i].active && s_connections[i].tcpSocket != INVALID_SOCKET)
{
closesocket(s_connections[i].tcpSocket);
s_connections[i].tcpSocket = INVALID_SOCKET;
app.DebugPrintf("Win64 LAN: Force-closed TCP connection for smallId=%d\n", smallId);
break;
}
closesocket(s_connections[smallId].tcpSocket);
s_connections[smallId].tcpSocket = INVALID_SOCKET;
app.DebugPrintf("Win64 LAN: Force-closed TCP connection for smallId=%d\n", smallId);
}
LeaveCriticalSection(&s_connectionsLock);
}
@@ -1150,9 +1192,9 @@ int NetworkSocketLayer::ClientRecvThreadProc(LPVOID param)
break;
}
int packetSize = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3];
int packetSize = ((uint32_t)header[0] << 24) | ((uint32_t)header[1] << 16) | ((uint32_t)header[2] << 8) | (uint32_t)header[3];
if (packetSize <= 0 || packetSize > NETWORK_LAN_MAX_PACKET_SIZE)
if (packetSize <= 0 || (unsigned int)packetSize > NETWORK_LAN_MAX_PACKET_SIZE)
{
app.DebugPrintf("LAN: Invalid packet size %d from host\n", packetSize);
break;
@@ -1161,7 +1203,6 @@ int NetworkSocketLayer::ClientRecvThreadProc(LPVOID param)
if ((int)recvBuf.size() < packetSize)
{
recvBuf.resize(packetSize);
app.DebugPrintf("LAN: Resized client recv buffer to %d bytes\n", packetSize);
}
if (!RecvExact(s_hostConnectionSocket, &recvBuf[0], packetSize))
@@ -1494,8 +1535,8 @@ std::vector<LANSession> NetworkSocketLayer::GetDiscoveredSessions()
int NetworkSocketLayer::DiscoveryThreadProc(LPVOID param)
{
app.DebugPrintf("Discovery thread started\n");
char recvBuf[1024];
const size_t MAX_DISCOVERED_SESSIONS = 64;
while (s_discovering)
{
@@ -1544,6 +1585,11 @@ int NetworkSocketLayer::DiscoveryThreadProc(LPVOID param)
if (broadcast->magic != NETWORK_LAN_BROADCAST_MAGIC)
continue;
broadcast->hostName[31] = L'\0';
for (int pn = 0; pn < 8; pn++)
broadcast->playerNames[pn][XUSER_NAME_SIZE - 1] = '\0';
char senderIP[64];
#if defined _XBOX
unsigned char *ipBytes = (unsigned char *)&senderAddr.sin_addr;
@@ -1586,6 +1632,12 @@ int NetworkSocketLayer::DiscoveryThreadProc(LPVOID param)
if (!found)
{
if (s_discoveredSessions.size() >= MAX_DISCOVERED_SESSIONS)
{
LeaveCriticalSection(&s_discoveryLock);
continue;
}
LANSession session;
memset(&session, 0, sizeof(session));
strncpy(session.hostIP, senderIP, sizeof(session.hostIP) - 1);