mirror of
https://github.com/LCEMP/LCEMP.git
synced 2026-07-26 19:37:07 +00:00
apply networking patches related to s
Fix Win64 LAN join failures and slot leaks, more than two players can join
This commit is contained in:
parent
db79e7d54c
commit
60f8613efb
|
|
@ -289,11 +289,24 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(ProfileManager.GetLockedProfile());
|
int lockedProfile = ProfileManager.GetLockedProfile();
|
||||||
|
if (lockedProfile < 0 || lockedProfile >= XUSER_MAX_COUNT)
|
||||||
|
lockedProfile = ProfileManager.GetPrimaryPad();
|
||||||
|
if (lockedProfile < 0 || lockedProfile >= XUSER_MAX_COUNT)
|
||||||
|
lockedProfile = 0;
|
||||||
|
|
||||||
|
INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(lockedProfile);
|
||||||
|
if(pNetworkPlayer == NULL)
|
||||||
|
{
|
||||||
|
// Fallback to primary pad if the locked profile didn't resolve.
|
||||||
|
int primary = ProfileManager.GetPrimaryPad();
|
||||||
|
if (primary >= 0 && primary < XUSER_MAX_COUNT)
|
||||||
|
pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(primary);
|
||||||
|
}
|
||||||
if(pNetworkPlayer == NULL)
|
if(pNetworkPlayer == NULL)
|
||||||
{
|
{
|
||||||
MinecraftServer::HaltServer();
|
MinecraftServer::HaltServer();
|
||||||
app.DebugPrintf("%d\n",ProfileManager.GetLockedProfile());
|
app.DebugPrintf("Join failed: no local player for locked=%d primary=%d\n", lockedProfile, ProfileManager.GetPrimaryPad());
|
||||||
// If the player is NULL here then something went wrong in the session setup, and continuing will end up in a crash
|
// If the player is NULL here then something went wrong in the session setup, and continuing will end up in a crash
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,14 @@ void CPlatformNetworkManagerStub::DoWork()
|
||||||
BYTE disconnectedSmallId;
|
BYTE disconnectedSmallId;
|
||||||
while (WinsockNetLayer::PopDisconnectedSmallId(&disconnectedSmallId))
|
while (WinsockNetLayer::PopDisconnectedSmallId(&disconnectedSmallId))
|
||||||
{
|
{
|
||||||
|
// Always free the smallId so a failed/aborted join doesn't permanently consume a slot.
|
||||||
|
if (disconnectedSmallId != 0)
|
||||||
|
WinsockNetLayer::PushFreeSmallId(disconnectedSmallId);
|
||||||
|
|
||||||
IQNetPlayer *qnetPlayer = m_pIQNet->GetPlayerBySmallId(disconnectedSmallId);
|
IQNetPlayer *qnetPlayer = m_pIQNet->GetPlayerBySmallId(disconnectedSmallId);
|
||||||
|
if (qnetPlayer == NULL && disconnectedSmallId < MINECRAFT_NET_MAX_PLAYERS)
|
||||||
|
qnetPlayer = &IQNet::m_player[disconnectedSmallId];
|
||||||
|
|
||||||
if (qnetPlayer != NULL && qnetPlayer->m_smallId == disconnectedSmallId)
|
if (qnetPlayer != NULL && qnetPlayer->m_smallId == disconnectedSmallId)
|
||||||
{
|
{
|
||||||
NotifyPlayerLeaving(qnetPlayer);
|
NotifyPlayerLeaving(qnetPlayer);
|
||||||
|
|
@ -235,32 +242,19 @@ void CPlatformNetworkManagerStub::DoWork()
|
||||||
qnetPlayer->m_isHostPlayer = false;
|
qnetPlayer->m_isHostPlayer = false;
|
||||||
qnetPlayer->m_gamertag[0] = 0;
|
qnetPlayer->m_gamertag[0] = 0;
|
||||||
qnetPlayer->SetCustomDataValue(0);
|
qnetPlayer->SetCustomDataValue(0);
|
||||||
WinsockNetLayer::PushFreeSmallId(disconnectedSmallId);
|
|
||||||
if (IQNet::s_playerCount > 1)
|
|
||||||
IQNet::s_playerCount--;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 1; i < MINECRAFT_NET_MAX_PLAYERS; i++)
|
// Recompute high-water mark so GetPlayerBySmallId doesn't miss active players.
|
||||||
{
|
DWORD newCount = 1;
|
||||||
IQNetPlayer *qp = &IQNet::m_player[i];
|
for (int i = MINECRAFT_NET_MAX_PLAYERS - 1; i >= 1; --i)
|
||||||
if (qp->GetCustomDataValue() == 0)
|
|
||||||
continue;
|
|
||||||
INetworkPlayer *np = (INetworkPlayer *)qp->GetCustomDataValue();
|
|
||||||
Socket *sock = np->GetSocket();
|
|
||||||
if (sock != NULL && sock->isClosing())
|
|
||||||
{
|
{
|
||||||
WinsockNetLayer::CloseConnectionBySmallId((BYTE)i);
|
if (IQNet::m_player[i].m_smallId == i)
|
||||||
|
{
|
||||||
|
newCount = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
IQNet::s_playerCount = newCount;
|
||||||
}
|
|
||||||
if (_iQNetStubState == QNET_STATE_GAME_PLAY && !m_pIQNet->IsHost())
|
|
||||||
{
|
|
||||||
if (!WinsockNetLayer::IsConnected() && !g_NetworkManager.IsLeavingGame())
|
|
||||||
{
|
|
||||||
if (app.GetDisconnectReason() == DisconnectPacket::eDisconnect_None)
|
|
||||||
app.SetDisconnectReason(DisconnectPacket::eDisconnect_Quitting);
|
|
||||||
app.SetAction(ProfileManager.GetPrimaryPad(), eAppAction_ExitWorld, (void *)TRUE);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -834,20 +828,9 @@ INetworkPlayer * CPlatformNetworkManagerStub::GetPlayerByXuid(PlayerUID xuid)
|
||||||
INetworkPlayer * CPlatformNetworkManagerStub::GetPlayerBySmallId(unsigned char smallId)
|
INetworkPlayer * CPlatformNetworkManagerStub::GetPlayerBySmallId(unsigned char smallId)
|
||||||
{
|
{
|
||||||
IQNetPlayer *qnetPlayer = m_pIQNet->GetPlayerBySmallId(smallId);
|
IQNetPlayer *qnetPlayer = m_pIQNet->GetPlayerBySmallId(smallId);
|
||||||
if (qnetPlayer == NULL)
|
if (qnetPlayer == NULL && smallId < MINECRAFT_NET_MAX_PLAYERS)
|
||||||
return NULL;
|
qnetPlayer = &IQNet::m_player[smallId];
|
||||||
|
return getNetworkPlayer(qnetPlayer);
|
||||||
INetworkPlayer *networkPlayer = getNetworkPlayer(qnetPlayer);
|
|
||||||
#ifdef _WINDOWS64
|
|
||||||
if (networkPlayer == NULL && smallId != 0 && !m_pIQNet->IsHost())
|
|
||||||
{
|
|
||||||
qnetPlayer->m_isRemote = true;
|
|
||||||
qnetPlayer->m_isHostPlayer = false;
|
|
||||||
NotifyPlayerJoined(qnetPlayer);
|
|
||||||
networkPlayer = getNetworkPlayer(qnetPlayer);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return networkPlayer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
INetworkPlayer *CPlatformNetworkManagerStub::GetHostPlayer()
|
INetworkPlayer *CPlatformNetworkManagerStub::GetHostPlayer()
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@ void PIXSetMarkerDeprecated(int a, char *b, ...) {}
|
||||||
|
|
||||||
bool IsEqualXUID(PlayerUID a, PlayerUID b)
|
bool IsEqualXUID(PlayerUID a, PlayerUID b)
|
||||||
{
|
{
|
||||||
#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) || defined(_DURANGO) || defined(_WINDOWS64)
|
#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) || defined(_DURANGO)
|
||||||
return (a == b);
|
return (a == b);
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -232,17 +232,13 @@ void Win64_SetupRemoteQNetPlayer(IQNetPlayer *player, BYTE smallId, bool isHost,
|
||||||
IQNet::s_playerCount = smallId + 1;
|
IQNet::s_playerCount = smallId + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Win64_IsActivePlayer(IQNetPlayer *p, DWORD index);
|
|
||||||
|
|
||||||
HRESULT IQNet::AddLocalPlayerByUserIndex(DWORD dwUserIndex){ return S_OK; }
|
HRESULT IQNet::AddLocalPlayerByUserIndex(DWORD dwUserIndex){ return S_OK; }
|
||||||
IQNetPlayer *IQNet::GetHostPlayer() { return &m_player[0]; }
|
IQNetPlayer *IQNet::GetHostPlayer() { return &m_player[0]; }
|
||||||
IQNetPlayer *IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex)
|
IQNetPlayer *IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex)
|
||||||
{
|
{
|
||||||
if (s_isHosting)
|
if (s_isHosting)
|
||||||
{
|
{
|
||||||
if (dwUserIndex < MINECRAFT_NET_MAX_PLAYERS &&
|
if (dwUserIndex < MINECRAFT_NET_MAX_PLAYERS && !m_player[dwUserIndex].m_isRemote)
|
||||||
!m_player[dwUserIndex].m_isRemote &&
|
|
||||||
Win64_IsActivePlayer(&m_player[dwUserIndex], dwUserIndex))
|
|
||||||
return &m_player[dwUserIndex];
|
return &m_player[dwUserIndex];
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -250,15 +246,22 @@ IQNetPlayer *IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex)
|
||||||
return NULL;
|
return NULL;
|
||||||
for (DWORD i = 0; i < s_playerCount; i++)
|
for (DWORD i = 0; i < s_playerCount; i++)
|
||||||
{
|
{
|
||||||
if (!m_player[i].m_isRemote && Win64_IsActivePlayer(&m_player[i], i))
|
if (!m_player[i].m_isRemote)
|
||||||
return &m_player[i];
|
{
|
||||||
|
// Require a valid smallId and attached network player to avoid
|
||||||
|
// returning unused slots on the client.
|
||||||
|
if (m_player[i].m_smallId == i && m_player[i].GetCustomDataValue() != 0)
|
||||||
|
return &m_player[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
static bool Win64_IsActivePlayer(IQNetPlayer *p, DWORD index)
|
static bool Win64_IsActivePlayer(IQNetPlayer *p, DWORD index)
|
||||||
{
|
{
|
||||||
if (index == 0) return true;
|
if (index == 0) return true;
|
||||||
return (p->GetCustomDataValue() != 0);
|
// Use smallId as the source of truth for activity; custom data can be cleared
|
||||||
|
// while the socket still needs to resolve the player.
|
||||||
|
return (p->m_smallId == index);
|
||||||
}
|
}
|
||||||
|
|
||||||
IQNetPlayer *IQNet::GetPlayerByIndex(DWORD dwPlayerIndex)
|
IQNetPlayer *IQNet::GetPlayerByIndex(DWORD dwPlayerIndex)
|
||||||
|
|
@ -276,21 +279,21 @@ IQNetPlayer *IQNet::GetPlayerByIndex(DWORD dwPlayerIndex)
|
||||||
}
|
}
|
||||||
IQNetPlayer *IQNet::GetPlayerBySmallId(BYTE SmallId)
|
IQNetPlayer *IQNet::GetPlayerBySmallId(BYTE SmallId)
|
||||||
{
|
{
|
||||||
if (SmallId >= MINECRAFT_NET_MAX_PLAYERS)
|
if (SmallId < MINECRAFT_NET_MAX_PLAYERS && m_player[SmallId].m_smallId == SmallId)
|
||||||
return NULL;
|
return &m_player[SmallId];
|
||||||
|
for (DWORD i = 0; i < s_playerCount; i++)
|
||||||
m_player[SmallId].m_smallId = SmallId;
|
{
|
||||||
if (SmallId >= s_playerCount)
|
if (m_player[i].m_smallId == SmallId && Win64_IsActivePlayer(&m_player[i], i)) return &m_player[i];
|
||||||
s_playerCount = SmallId + 1;
|
}
|
||||||
return &m_player[SmallId];
|
return NULL;
|
||||||
}
|
}
|
||||||
IQNetPlayer *IQNet::GetPlayerByXuid(PlayerUID xuid)
|
IQNetPlayer *IQNet::GetPlayerByXuid(PlayerUID xuid)
|
||||||
{
|
{
|
||||||
for (DWORD i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
|
for (DWORD i = 0; i < s_playerCount; i++)
|
||||||
{
|
{
|
||||||
if (Win64_IsActivePlayer(&m_player[i], i) && m_player[i].GetXuid() == xuid) return &m_player[i];
|
if (Win64_IsActivePlayer(&m_player[i], i) && m_player[i].GetXuid() == xuid) return &m_player[i];
|
||||||
}
|
}
|
||||||
return NULL;
|
return &m_player[0];
|
||||||
}
|
}
|
||||||
DWORD IQNet::GetPlayerCount()
|
DWORD IQNet::GetPlayerCount()
|
||||||
{
|
{
|
||||||
|
|
@ -305,28 +308,15 @@ QNET_STATE IQNet::GetState() { return _iQNetStubState; }
|
||||||
bool IQNet::IsHost() { return s_isHosting; }
|
bool IQNet::IsHost() { return s_isHosting; }
|
||||||
HRESULT IQNet::JoinGameFromInviteInfo(DWORD dwUserIndex, DWORD dwUserMask, const INVITE_INFO *pInviteInfo) { return S_OK; }
|
HRESULT IQNet::JoinGameFromInviteInfo(DWORD dwUserIndex, DWORD dwUserMask, const INVITE_INFO *pInviteInfo) { return S_OK; }
|
||||||
void IQNet::HostGame() { _iQNetStubState = QNET_STATE_SESSION_STARTING; s_isHosting = true; }
|
void IQNet::HostGame() { _iQNetStubState = QNET_STATE_SESSION_STARTING; s_isHosting = true; }
|
||||||
void IQNet::ClientJoinGame()
|
void IQNet::ClientJoinGame() { _iQNetStubState = QNET_STATE_SESSION_STARTING; s_isHosting = false; }
|
||||||
{
|
|
||||||
_iQNetStubState = QNET_STATE_SESSION_STARTING;
|
|
||||||
s_isHosting = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
|
|
||||||
{
|
|
||||||
m_player[i].m_smallId = (BYTE)i;
|
|
||||||
m_player[i].m_isRemote = true;
|
|
||||||
m_player[i].m_isHostPlayer = false;
|
|
||||||
m_player[i].m_gamertag[0] = 0;
|
|
||||||
m_player[i].SetCustomDataValue(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void IQNet::EndGame()
|
void IQNet::EndGame()
|
||||||
{
|
{
|
||||||
_iQNetStubState = QNET_STATE_IDLE;
|
_iQNetStubState = QNET_STATE_IDLE;
|
||||||
s_isHosting = false;
|
s_isHosting = false;
|
||||||
s_playerCount = 1;
|
s_playerCount = 1;
|
||||||
for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
|
for (int i = 1; i < MINECRAFT_NET_MAX_PLAYERS; i++)
|
||||||
{
|
{
|
||||||
m_player[i].m_smallId = (BYTE)i;
|
m_player[i].m_smallId = 0;
|
||||||
m_player[i].m_isRemote = false;
|
m_player[i].m_isRemote = false;
|
||||||
m_player[i].m_isHostPlayer = false;
|
m_player[i].m_isHostPlayer = false;
|
||||||
m_player[i].m_gamertag[0] = 0;
|
m_player[i].m_gamertag[0] = 0;
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,9 @@
|
||||||
#include "..\Minecraft.World\net.minecraft.world.item.h"
|
#include "..\Minecraft.World\net.minecraft.world.item.h"
|
||||||
#include "..\Minecraft.World\SharedConstants.h"
|
#include "..\Minecraft.World\SharedConstants.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
#include "Windows64\\Network\\WinsockNetLayer.h"
|
||||||
|
#endif
|
||||||
// #ifdef __PS3__
|
// #ifdef __PS3__
|
||||||
// #include "PS3\Network\NetworkPlayerSony.h"
|
// #include "PS3\Network\NetworkPlayerSony.h"
|
||||||
// #endif
|
// #endif
|
||||||
|
|
@ -65,6 +68,24 @@ void PendingConnection::disconnect(DisconnectPacket::eDisconnectReason reason)
|
||||||
// try { // 4J - removed try/catch
|
// try { // 4J - removed try/catch
|
||||||
// logger.info("Disconnecting " + getName() + ": " + reason);
|
// logger.info("Disconnecting " + getName() + ": " + reason);
|
||||||
app.DebugPrintf("Pending connection disconnect: %d\n", reason );
|
app.DebugPrintf("Pending connection disconnect: %d\n", reason );
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
// Ensure the underlying Win64 TCP connection is closed so the slot is freed.
|
||||||
|
if (connection != NULL)
|
||||||
|
{
|
||||||
|
Socket *sock = connection->getSocket();
|
||||||
|
INetworkPlayer *np = sock ? sock->getPlayer() : NULL;
|
||||||
|
if (np != NULL && !np->IsLocal())
|
||||||
|
{
|
||||||
|
WinsockNetLayer::DisconnectSmallId(np->GetSmallId());
|
||||||
|
}
|
||||||
|
else if (sock != NULL)
|
||||||
|
{
|
||||||
|
BYTE sid = sock->getSmallId();
|
||||||
|
if (sid != 0)
|
||||||
|
WinsockNetLayer::DisconnectSmallId(sid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
connection->send( shared_ptr<DisconnectPacket>( new DisconnectPacket(reason) ) );
|
connection->send( shared_ptr<DisconnectPacket>( new DisconnectPacket(reason) ) );
|
||||||
connection->sendAndQuit();
|
connection->sendAndQuit();
|
||||||
done = true;
|
done = true;
|
||||||
|
|
@ -294,4 +315,4 @@ wstring PendingConnection::getName()
|
||||||
bool PendingConnection::isServerPacketListener()
|
bool PendingConnection::isServerPacketListener()
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,11 @@ class PendingConnection : public PacketListener
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
static const int FAKE_LAG = 0;
|
static const int FAKE_LAG = 0;
|
||||||
|
#ifdef _WINDOWS64
|
||||||
|
static const int MAX_TICKS_BEFORE_LOGIN = 20 * 5;
|
||||||
|
#else
|
||||||
static const int MAX_TICKS_BEFORE_LOGIN = 20 * 30;
|
static const int MAX_TICKS_BEFORE_LOGIN = 20 * 30;
|
||||||
|
#endif
|
||||||
|
|
||||||
// public static Logger logger = Logger.getLogger("Minecraft");
|
// public static Logger logger = Logger.getLogger("Minecraft");
|
||||||
static Random *random;
|
static Random *random;
|
||||||
|
|
@ -45,4 +49,4 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void sendPreLoginResponse();
|
void sendPreLoginResponse();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -213,14 +213,6 @@ bool WinsockNetLayer::JoinGame(const char *ip, int port)
|
||||||
|
|
||||||
s_isHost = false;
|
s_isHost = false;
|
||||||
s_hostSmallId = 0;
|
s_hostSmallId = 0;
|
||||||
s_connected = false;
|
|
||||||
s_active = false;
|
|
||||||
|
|
||||||
if (s_hostConnectionSocket != INVALID_SOCKET)
|
|
||||||
{
|
|
||||||
closesocket(s_hostConnectionSocket);
|
|
||||||
s_hostConnectionSocket = INVALID_SOCKET;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct addrinfo hints = {};
|
struct addrinfo hints = {};
|
||||||
struct addrinfo *result = NULL;
|
struct addrinfo *result = NULL;
|
||||||
|
|
@ -239,55 +231,37 @@ bool WinsockNetLayer::JoinGame(const char *ip, int port)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool connected = false;
|
s_hostConnectionSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
|
||||||
BYTE assignedSmallId = 0;
|
if (s_hostConnectionSocket == INVALID_SOCKET)
|
||||||
const int maxAttempts = 12;
|
|
||||||
|
|
||||||
for (int attempt = 0; attempt < maxAttempts; ++attempt)
|
|
||||||
{
|
|
||||||
s_hostConnectionSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
|
|
||||||
if (s_hostConnectionSocket == INVALID_SOCKET)
|
|
||||||
{
|
|
||||||
app.DebugPrintf("socket() failed: %d\n", WSAGetLastError());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int noDelay = 1;
|
|
||||||
setsockopt(s_hostConnectionSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay));
|
|
||||||
|
|
||||||
iResult = connect(s_hostConnectionSocket, result->ai_addr, (int)result->ai_addrlen);
|
|
||||||
if (iResult == SOCKET_ERROR)
|
|
||||||
{
|
|
||||||
int err = WSAGetLastError();
|
|
||||||
app.DebugPrintf("connect() to %s:%d failed (attempt %d/%d): %d\n", ip, port, attempt + 1, maxAttempts, err);
|
|
||||||
closesocket(s_hostConnectionSocket);
|
|
||||||
s_hostConnectionSocket = INVALID_SOCKET;
|
|
||||||
Sleep(200);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
BYTE assignBuf[1];
|
|
||||||
int bytesRecv = recv(s_hostConnectionSocket, (char *)assignBuf, 1, 0);
|
|
||||||
if (bytesRecv != 1)
|
|
||||||
{
|
|
||||||
app.DebugPrintf("Failed to receive small ID assignment from host (attempt %d/%d)\n", attempt + 1, maxAttempts);
|
|
||||||
closesocket(s_hostConnectionSocket);
|
|
||||||
s_hostConnectionSocket = INVALID_SOCKET;
|
|
||||||
Sleep(200);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
assignedSmallId = assignBuf[0];
|
|
||||||
connected = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
freeaddrinfo(result);
|
|
||||||
|
|
||||||
if (!connected)
|
|
||||||
{
|
{
|
||||||
|
app.DebugPrintf("socket() failed: %d\n", WSAGetLastError());
|
||||||
|
freeaddrinfo(result);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
s_localSmallId = assignedSmallId;
|
|
||||||
|
int noDelay = 1;
|
||||||
|
setsockopt(s_hostConnectionSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay));
|
||||||
|
|
||||||
|
iResult = connect(s_hostConnectionSocket, result->ai_addr, (int)result->ai_addrlen);
|
||||||
|
freeaddrinfo(result);
|
||||||
|
if (iResult == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
app.DebugPrintf("connect() to %s:%d failed: %d\n", ip, port, WSAGetLastError());
|
||||||
|
closesocket(s_hostConnectionSocket);
|
||||||
|
s_hostConnectionSocket = INVALID_SOCKET;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BYTE assignBuf[1];
|
||||||
|
int bytesRecv = recv(s_hostConnectionSocket, (char *)assignBuf, 1, 0);
|
||||||
|
if (bytesRecv != 1)
|
||||||
|
{
|
||||||
|
app.DebugPrintf("Failed to receive small ID assignment from host\n");
|
||||||
|
closesocket(s_hostConnectionSocket);
|
||||||
|
s_hostConnectionSocket = INVALID_SOCKET;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
s_localSmallId = assignBuf[0];
|
||||||
|
|
||||||
app.DebugPrintf("Win64 LAN: Connected to %s:%d, assigned smallId=%d\n", ip, port, s_localSmallId);
|
app.DebugPrintf("Win64 LAN: Connected to %s:%d, assigned smallId=%d\n", ip, port, s_localSmallId);
|
||||||
|
|
||||||
|
|
@ -447,6 +421,8 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
LeaveCriticalSection(&s_freeSmallIdLock);
|
LeaveCriticalSection(&s_freeSmallIdLock);
|
||||||
|
app.DebugPrintf("Win64 LAN: Allocated smallId=%d (next=%d, free=%u)\n",
|
||||||
|
assignedSmallId, s_nextSmallId, (unsigned int)s_freeSmallIds.size());
|
||||||
|
|
||||||
BYTE assignBuf[1] = { assignedSmallId };
|
BYTE assignBuf[1] = { assignedSmallId };
|
||||||
int sent = send(clientSocket, (const char *)assignBuf, 1, 0);
|
int sent = send(clientSocket, (const char *)assignBuf, 1, 0);
|
||||||
|
|
@ -454,6 +430,7 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
|
||||||
{
|
{
|
||||||
app.DebugPrintf("Failed to send small ID to client\n");
|
app.DebugPrintf("Failed to send small ID to client\n");
|
||||||
closesocket(clientSocket);
|
closesocket(clientSocket);
|
||||||
|
PushFreeSmallId(assignedSmallId);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -505,8 +482,7 @@ DWORD WINAPI WinsockNetLayer::RecvThreadProc(LPVOID param)
|
||||||
BYTE clientSmallId = s_connections[connIdx].smallId;
|
BYTE clientSmallId = s_connections[connIdx].smallId;
|
||||||
LeaveCriticalSection(&s_connectionsLock);
|
LeaveCriticalSection(&s_connectionsLock);
|
||||||
|
|
||||||
std::vector<BYTE> recvBuf;
|
BYTE *recvBuf = new BYTE[WIN64_NET_RECV_BUFFER_SIZE];
|
||||||
recvBuf.resize(WIN64_NET_RECV_BUFFER_SIZE);
|
|
||||||
|
|
||||||
while (s_active)
|
while (s_active)
|
||||||
{
|
{
|
||||||
|
|
@ -517,47 +493,34 @@ DWORD WINAPI WinsockNetLayer::RecvThreadProc(LPVOID param)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int packetSize =
|
int packetSize = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3];
|
||||||
((uint32_t)header[0] << 24) |
|
|
||||||
((uint32_t)header[1] << 16) |
|
|
||||||
((uint32_t)header[2] << 8) |
|
|
||||||
((uint32_t)header[3]);
|
|
||||||
|
|
||||||
if (packetSize <= 0 || packetSize > WIN64_NET_MAX_PACKET_SIZE)
|
if (packetSize <= 0 || packetSize > WIN64_NET_RECV_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
app.DebugPrintf("Win64 LAN: Invalid packet size %d from client smallId=%d (max=%d)\n",
|
app.DebugPrintf("Win64 LAN: Invalid packet size %d from client smallId=%d\n", packetSize, clientSmallId);
|
||||||
packetSize,
|
|
||||||
clientSmallId,
|
|
||||||
(int)WIN64_NET_MAX_PACKET_SIZE);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((int)recvBuf.size() < packetSize)
|
if (!RecvExact(sock, recvBuf, packetSize))
|
||||||
{
|
|
||||||
recvBuf.resize(packetSize);
|
|
||||||
app.DebugPrintf("Win64 LAN: Resized host recv buffer to %d bytes for client smallId=%d\n", packetSize, clientSmallId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!RecvExact(sock, &recvBuf[0], packetSize))
|
|
||||||
{
|
{
|
||||||
app.DebugPrintf("Win64 LAN: Client smallId=%d disconnected (body)\n", clientSmallId);
|
app.DebugPrintf("Win64 LAN: Client smallId=%d disconnected (body)\n", clientSmallId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleDataReceived(clientSmallId, s_hostSmallId, &recvBuf[0], packetSize);
|
HandleDataReceived(clientSmallId, s_hostSmallId, recvBuf, packetSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete[] recvBuf;
|
||||||
|
app.DebugPrintf("Win64 LAN: RecvThread ending for smallId=%d\n", clientSmallId);
|
||||||
|
|
||||||
EnterCriticalSection(&s_connectionsLock);
|
EnterCriticalSection(&s_connectionsLock);
|
||||||
for (size_t i = 0; i < s_connections.size(); i++)
|
for (size_t i = 0; i < s_connections.size(); i++)
|
||||||
{
|
{
|
||||||
if (s_connections[i].smallId == clientSmallId)
|
if (s_connections[i].smallId == clientSmallId)
|
||||||
{
|
{
|
||||||
s_connections[i].active = false;
|
s_connections[i].active = false;
|
||||||
if (s_connections[i].tcpSocket != INVALID_SOCKET)
|
closesocket(s_connections[i].tcpSocket);
|
||||||
{
|
s_connections[i].tcpSocket = INVALID_SOCKET;
|
||||||
closesocket(s_connections[i].tcpSocket);
|
|
||||||
s_connections[i].tcpSocket = INVALID_SOCKET;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -581,6 +544,8 @@ bool WinsockNetLayer::PopDisconnectedSmallId(BYTE *outSmallId)
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
LeaveCriticalSection(&s_disconnectLock);
|
LeaveCriticalSection(&s_disconnectLock);
|
||||||
|
if (found)
|
||||||
|
app.DebugPrintf("Win64 LAN: Popped disconnected smallId=%d\n", *outSmallId);
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -589,28 +554,50 @@ void WinsockNetLayer::PushFreeSmallId(BYTE smallId)
|
||||||
EnterCriticalSection(&s_freeSmallIdLock);
|
EnterCriticalSection(&s_freeSmallIdLock);
|
||||||
s_freeSmallIds.push_back(smallId);
|
s_freeSmallIds.push_back(smallId);
|
||||||
LeaveCriticalSection(&s_freeSmallIdLock);
|
LeaveCriticalSection(&s_freeSmallIdLock);
|
||||||
|
app.DebugPrintf("Win64 LAN: Freed smallId=%d (free=%u)\n", smallId, (unsigned int)s_freeSmallIds.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void WinsockNetLayer::CloseConnectionBySmallId(BYTE smallId)
|
void WinsockNetLayer::DisconnectSmallId(BYTE smallId)
|
||||||
{
|
{
|
||||||
|
if (!s_active) return;
|
||||||
|
|
||||||
|
HANDLE recvThread = NULL;
|
||||||
|
bool closed = false;
|
||||||
|
|
||||||
EnterCriticalSection(&s_connectionsLock);
|
EnterCriticalSection(&s_connectionsLock);
|
||||||
for (size_t i = 0; i < s_connections.size(); i++)
|
for (size_t i = 0; i < s_connections.size(); i++)
|
||||||
{
|
{
|
||||||
if (s_connections[i].smallId == smallId && s_connections[i].active && s_connections[i].tcpSocket != INVALID_SOCKET)
|
if (s_connections[i].smallId == smallId && s_connections[i].active)
|
||||||
{
|
{
|
||||||
closesocket(s_connections[i].tcpSocket);
|
s_connections[i].active = false;
|
||||||
s_connections[i].tcpSocket = INVALID_SOCKET;
|
recvThread = s_connections[i].recvThread;
|
||||||
app.DebugPrintf("Win64 LAN: Force-closed TCP connection for smallId=%d\n", smallId);
|
if (s_connections[i].tcpSocket != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
closesocket(s_connections[i].tcpSocket);
|
||||||
|
s_connections[i].tcpSocket = INVALID_SOCKET;
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LeaveCriticalSection(&s_connectionsLock);
|
LeaveCriticalSection(&s_connectionsLock);
|
||||||
|
|
||||||
|
if (closed)
|
||||||
|
{
|
||||||
|
app.DebugPrintf("Win64 LAN: Forced disconnect smallId=%d\n", smallId);
|
||||||
|
// If there's no recv thread to report this, queue it now.
|
||||||
|
if (recvThread == NULL)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&s_disconnectLock);
|
||||||
|
s_disconnectedSmallIds.push_back(smallId);
|
||||||
|
LeaveCriticalSection(&s_disconnectLock);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI WinsockNetLayer::ClientRecvThreadProc(LPVOID param)
|
DWORD WINAPI WinsockNetLayer::ClientRecvThreadProc(LPVOID param)
|
||||||
{
|
{
|
||||||
std::vector<BYTE> recvBuf;
|
BYTE *recvBuf = new BYTE[WIN64_NET_RECV_BUFFER_SIZE];
|
||||||
recvBuf.resize(WIN64_NET_RECV_BUFFER_SIZE);
|
|
||||||
|
|
||||||
while (s_active && s_hostConnectionSocket != INVALID_SOCKET)
|
while (s_active && s_hostConnectionSocket != INVALID_SOCKET)
|
||||||
{
|
{
|
||||||
|
|
@ -623,29 +610,23 @@ DWORD WINAPI WinsockNetLayer::ClientRecvThreadProc(LPVOID param)
|
||||||
|
|
||||||
int packetSize = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3];
|
int packetSize = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3];
|
||||||
|
|
||||||
if (packetSize <= 0 || packetSize > WIN64_NET_MAX_PACKET_SIZE)
|
if (packetSize <= 0 || packetSize > WIN64_NET_RECV_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
app.DebugPrintf("Win64 LAN: Invalid packet size %d from host (max=%d)\n",
|
app.DebugPrintf("Win64 LAN: Invalid packet size %d from host\n", packetSize);
|
||||||
packetSize,
|
|
||||||
(int)WIN64_NET_MAX_PACKET_SIZE);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((int)recvBuf.size() < packetSize)
|
if (!RecvExact(s_hostConnectionSocket, recvBuf, packetSize))
|
||||||
{
|
|
||||||
recvBuf.resize(packetSize);
|
|
||||||
app.DebugPrintf("Win64 LAN: Resized client recv buffer to %d bytes\n", packetSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!RecvExact(s_hostConnectionSocket, &recvBuf[0], packetSize))
|
|
||||||
{
|
{
|
||||||
app.DebugPrintf("Win64 LAN: Disconnected from host (body)\n");
|
app.DebugPrintf("Win64 LAN: Disconnected from host (body)\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleDataReceived(s_hostSmallId, s_localSmallId, &recvBuf[0], packetSize);
|
HandleDataReceived(s_hostSmallId, s_localSmallId, recvBuf, packetSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete[] recvBuf;
|
||||||
|
|
||||||
s_connected = false;
|
s_connected = false;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
#define WIN64_NET_DEFAULT_PORT 25565
|
#define WIN64_NET_DEFAULT_PORT 25565
|
||||||
#define WIN64_NET_MAX_CLIENTS 7
|
#define WIN64_NET_MAX_CLIENTS 7
|
||||||
#define WIN64_NET_RECV_BUFFER_SIZE 65536
|
#define WIN64_NET_RECV_BUFFER_SIZE 65536
|
||||||
#define WIN64_NET_MAX_PACKET_SIZE (4 * 1024 * 1024)
|
|
||||||
#define WIN64_LAN_DISCOVERY_PORT 25566
|
#define WIN64_LAN_DISCOVERY_PORT 25566
|
||||||
#define WIN64_LAN_BROADCAST_MAGIC 0x4D434C4E
|
#define WIN64_LAN_BROADCAST_MAGIC 0x4D434C4E
|
||||||
|
|
||||||
|
|
@ -82,7 +81,7 @@ public:
|
||||||
|
|
||||||
static bool PopDisconnectedSmallId(BYTE *outSmallId);
|
static bool PopDisconnectedSmallId(BYTE *outSmallId);
|
||||||
static void PushFreeSmallId(BYTE smallId);
|
static void PushFreeSmallId(BYTE smallId);
|
||||||
static void CloseConnectionBySmallId(BYTE smallId);
|
static void DisconnectSmallId(BYTE smallId);
|
||||||
|
|
||||||
static bool StartAdvertising(int gamePort, const wchar_t *hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer);
|
static bool StartAdvertising(int gamePort, const wchar_t *hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer);
|
||||||
static void StopAdvertising();
|
static void StopAdvertising();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue